Disclaimer: The purpose of the Open Case Studies project is to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data. A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given data set, and should not be used in the context of making policy decisions without external consultation from scientific experts.

This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 (CC BY-NC 3.0) United States License.

To cite this case study please use:

Wright, Carrie, and Ontiveros, Michael and Jager, Leah and Taub, Margaret and Hicks, Stephanie. (2020). https://github.com/opencasestudies/ocs-youth-disconnection-case-study. Disparities in Youth Disconnection (Version v1.0.0).

Motivation


According to this report youth disconnection although generally showing decreasing trends for the past 7 years, shows racial and ethnic disparities, where some groups are showing increased rates of disconnection.

So what does the term “youth disconnection” mean?

According to Measure of America (a nonpartisan project of the nonprofit Social Science Research Council that is focused on opportunity in the United States) disconnected youth are:

“young people between the ages of 16 and 24 who are neither working nor in school

They state that such disconnection hinders these individuals to aquire skills and create relationships necessary to have a sucessful adulthood.

They state that:

“people who experience a period of disconnection as young adults go on to earn less and are less likely to be employed, own a home, or report good health by the time they reach their thirties”

Disconnected youth are also referred to as opportunity youth, which has the added positive connotation that promoting such individuals can be beneficial not only for these individuals but also for their communties and for society.

We will expand beyond the Measure of America annual report to take a deeper look at differences of specific groups of youths. Identifying youths particularly at risk or disconnected, can help inform the design of targeted prevention and rengagement strategies.

This case study is motivated by this article:

Mendelson, T., Mmari, K., Blum, R. W., Catalano, R. F. & Brindis, C. D. Opportunity Youth: Insights and Opportunities for a Public Health Approach to Reengage Disconnected Teenagers and Young Adults. Public Health Rep 133, 54S-64S (2018).

This article describes strategies for prevention of disconnection and reengagement of discconnected youth and how such interventions could greatly positively impact opportunity youth for the entire trajectory of their lives and for future generations. It also points out that indeed their are disparities among different racial/ethnic groups.

Main Questions


Our main questions:

  1. How have youth disconnection rates in American youth changed since 2008?
  2. In particular, how has this changed for different gender and ethnic groups? Are any groups particularly disconnected?

Learning Objectives


In this case study, we will demonstrate how to import and wrangle data available in the Portable Document Format (PDF). We will especially focus on using packages and functions from the Tidyverse, such as dplyr, ggplot2. The tidyverse is a library of packages created by RStudio. While some students may be familiar with previous R programming packages, these packages make data science in R more legible and intuitive.

The skills, methods, and concepts that students will be familiar with by the end of this case study are:

Data science skills:

  1. Importing data from PDF files using the magick package
  2. Apply action verbs in dplyr for data wrangling
  3. How to pivot between “long” and “wide” datasets (tidyr)
  4. Joining together multiple datasets using dplyr
  5. How to create data visualizations with ggplot2 that are in a similar style to an existing image

Statistical concepts and methods:

  1. Implementation of the Mann-Kendall trend test
  2. Interpretation of the Mann-Kendall trend test


We will begin by loading the packages that we will need:

Package Use
here to easily load and save data
tidyverse for data science operations
pdftools to manage PDF documents
magick for image processing
here to easily load and save data
tidyverse for data science operations
pdftools to manage PDF documents
magick for image processing

The first time we use a function, we will use the :: to indicate which package we are using. Unless we have overlapping function names, this is not necessary, but we will include it here to be informative about where the functions we will use come from.

Context


So how does youth disconnection happen and what impact does it have?

There are many known risk factors, which have been identified in a variety of contexts (from family, friends, school, community, society) including:

  • poverty (disconnected youth are nearly twice as likely to live in poverty and receive Medicaid)
  • racial/ethnic disparities (findings suggest that these persist even when controlling for income)
  • residential environment (in 2016 while 11.7% was the national average, 24% of people age 16-24 in the rural South were disconnected)
  • poor academic performance
  • poor mental health
  • substance use disorders
  • parental unemployment
  • trauma exposure
  • association with socially deviant peers
  • school policies such as “one strike and you’re out” - which is a zero tolerance school expulsion policy and shown to increase dropouts and incarceration rates

These risk factors make it more likely for young people to miss out on education, training, and networking that can act as a foundation for a sucessful career.

There are also many known negative consequences associated with youth disconnection including but not limited to:

  • chronic unemployment
  • poverty
  • poor menthal health and poor general health (in a 2002 study - youths discoonected for 6 or more months were 3 times more likely to develop depression or other mental health disorder)
  • crimial behavior (in a 2002 study - youths discoonected for 6 or more months were 5 times more likely to have a criminal record)
  • incarceration
  • early mortality

Photo by Jon Tyson on Unsplash

Furthermore, in 2012 it was estimated that each disconnected youth costs taxpayers $250000 during a life time due to lost tax revenue and costs for social sercices, heath care and criminal justice.

Youth disconnection can be described as a continuum, as some youths will be disconnected for a brief time, while others are chronically disconnected. Additionally, while an individual who is out of school and work and also has poor support from the realtionships of others may be further disconnected than an individual who has social support.

Here is an illustration of risk factors, protective factors and the continuum of disconnection:

##### [source]

Strategies to mitigate youth disconnection

Many programs have identified useful strategies in rengaging disconnected youth or preventing discconection of youth.

generally speaking, most programs focus on reengagement strategies, however, prevention strategies are likely to be just as important.

Reserach suggests that active involvement with at risk youth from infancy and across multiple developmental stages through young adulthood whould be the most beneficial.

In fact, the quality of parental caregiving of infants age 6-24 months has actually been shown to be a predictor of high school dropout rates! Thus early interventions may be very important and consistent continual engagement may prevent further disconnection of youths.

Prevention strategies include:

See here and here for listings of programs dedicated to rengaging disconnected youth or preventing disconnection.

See here and here for particular examples.

The statistics used in this section came from this article.

Limitations


There are some important considerations regarding this data analysis to keep in mind:

  1. This data used in the Measure of America project reports from the is derived from American Community Survey(ASC) which excludes or underrepresents certain opportunity youth groups, such as youths in the juvenile justice system, youths in the foster care system, and homeless youths as the survey is conducted on households. Furthermore, youths who may be more disconnected for other reasons besides not being in work or school, such as dealing with the added challenge of being a teenage mother, or being abused is not available in this dataset. Thus, this data likely underestimates youth disconnection rates.

  2. Data about certain group intersections (meaning for example individuals of a particular gender and ethnicity) or particular groups in general such as specific ethnicities or gender or sexual identity groups such as LGBT (lesbian/gay/bisexual/transgender/queer and questioning) or nonbinary gender populations is unfortunately not available in the data used in this analysis and in most research about this topic. Luckily however, recent years of the ACS survey has more detailed infromation about a greater number of racial and ethnic groups and racial/ethnic intersections.

  3. The statistical procedures we are using may be overly simplistic. In all data analysis, we need to be wary about deriving meaning from the statistical procedures we use.

  4. Using image processing tools can be very helpful. The manner in which data is obtained with image processing tools is what we would describe as a black box process, a process with known inputs and outputs but unknown mechanics. Because we are unaware of how our outputs are generated from our inputs, we need to be wary of the output. With the small output we are creating in this case study, a visual inspection should suffice.

What are the data?


In this case study we will be using data related to youth disconnection from the two following reports from the Measure of America project:

Measure of America is a nonpartisan project of the nonprofit Social Science Research Council founded in 2007 to create easy-to-use yet methodologically sound tools for understanding well-being and opportunity in America. Through reports, interactive apps, and custom-built dashboards, Measure of America works with partners to breathe life into numbers, using data to identify areas of highest need, pinpoint levers for change, and track progress over time.

  1. Lewis, Kristen. Making the Connection: Transportation and Youth Disconnection . New York: Measure of America, Social Science Research Council, 2019. (Data up to 2017)

  1. : Lewis, Kristen. A Decade Undone: Youth Disconnection in the Age of Coronavirus. New York: Measure of America, Social Science Research Council, 2020. (Data up to 2018)

The data used in these reports comes from the American Community Survey(ASC), which is the largest survey conducted by the United States Census Bureau. The survey started in 2005 and collects data for 3.5 million households annually. Data is collected about ancestry, citizehsip, income, employment, disability among many other aspects. See here for more detailed information about the survey.

According to Wikipedia (https://en.wikipedia.org/wiki/American_Community_Survey):

Data is collected by internet, mail, telephone interviews and in-person interviews…About 95 percent of households across all response modes ultimately respond… ACS responses are confidential… and “immune from legal process”

It is a mandatory survey, it is governed by federal laws that could impose a fine of as much as $5,000 for refusing to participate.

We are particularlly interesed in the following tables on the last page of the Measure of America 2019 report:

We are particularlly interesed in the tables on the following pages from the Measure of America 2020 report:

Data Import


One way to import data from a pdf is to use the pdf_text() function of the pdftools package. The here() function of the here package can allow us to specify where the document that we want to import is located easily, starting from the directory where a .Rproj file is located. In this case, we will import the Making_the_Connection.pdf in the docs directory. Note this is the case if you pull the repository from github.

We can take a look at the output for the page with our table of interests by simpy using brackets [] around the page number. The page we are interested in (athough called 39 in the report) is the 44th page, which looks like this:

[1] "Youth Disconnection by Gender and by Race and Ethnicity\n                                                                                                                                               I NDI CATOR TA BLE S\n                                DISCONNECTED YOUTH\nMAJOR RACIAL AND                 RATE (% ages 16–24)                                  2017          CHANGE IN RATE\nETHNIC GROUPS            2008   2010       2012           2014     2016        (%)           (#)     2010–2017 (%)\nUnited States            12.6   14.7       14.1           13.2     11.7        11.5     4,501,800       -22.1\nMale                     12.3   15.2       14.5           13.3     12.1        11.8     2,382,500       -22.5\nFemale                   12.9   14.1       13.7           13.0     11.2        11.1     2,119,400       -21.7\nASIAN                    7.1     8.5       7.8            7.9       6.6        6.6      145,600         -21.7\nAsian Male               6.3     8.3          7.4         7.2       6.7        6.5       73,000         -21.4\nAsian Female             7.9     8.6          8.1         8.6       6.6        6.7       72,600         -22.0\nWHITE                    9.7    11.7       11.2           10.8      9.7        9.4      1,961,700       -20.1\nWhite Male               9.5    12.3       11.5           10.8    10.0         9.6      1,031,200       -22.4\nWhite Female             10.0   11.1       10.8           10.7      9.4        9.1       930,600        -17.4\nLATINO                   16.7   18.5       17.3           15.2     13.7        13.2     1,157,300       -28.7\nLatino Male              13.6   16.8       16.0           14.0     12.6        12.4      562,600        -26.0\nLatina Female            20.2   20.3       18.8           16.5     14.8        13.9      594,700        -31.5\nBLACK                    20.4   22.5       22.4           20.6     17.2        17.9     999,700         -20.6\nBlack Male               23.7   26.0       25.6           23.5     20.1        20.8      591,600        -19.8\nBlack Female             17.0   19.0       19.3           17.6     14.2        14.8      408,000        -22.1\nNATIVE AMERICAN          24.4   28.8       27.0           26.3     25.8        23.9      67,700         -17.1\nNative American Male     25.0   30.9       28.0           26.9     28.1        23.3      33,200         -24.5\nNative American Female   23.9   26.7       25.9           25.6     23.4        24.5      34,500         -8.4\n                                       2017                                                                            2017\n ASIAN SUBGROUPS                (%)                 (#)          LATINO SUBGROUPS                               (%)             (#)\n United States                  11.5       4,501,800\n Male                           11.8          2,382,500          LATINO                                         13.2          1,157,300\n Female                         11.1          2,119,400          Latino Male                                    12.4           562,600\n ASIAN                          6.6           145,600            Latina Female                                  13.9           594,700\n Asian Male                     6.5            73,000            SOUTH AMERICAN                                 8.4            37,600\n Asian Female                   6.7            72,600            South American Male                            9.1            20,400\n CHINESE                        4.3            23,800            South American Female                          7.7            17,200\n Chinese Male                   4.7            12,700            CENTRAL AMERICAN                               12.0           93,100\n Chinese Female                 3.9            11,100            Central American Male                          9.3            37,900\n VIETNAMESE                     5.5            13,500            Central American Female                        15.0           55,200\n Vietnamese Male                7.5             9,300\n                                                                 MEXICAN                                        13.3          762,400\n Vietnamese Female              3.4             4,200\n                                                                 Mexican Male                                   12.2           358,200\nINDIAN                          5.9            22,300\n                                                                 Mexican Female                                 14.4           404,200\nIndian Male                     4.1             8,000            OTHER LATINO                                   13.6           44,800\nIndian Female                   7.8            14,300\n                                                                 Other Latino Male                              15.3           27,600\n PAKISTANI                      6.4             4,900\n                                                                 Other Latina Female                            11.5           17,300\n Pakistani Male\n                                                                 PUERTO RICAN, DOMINICAN, CUBAN                 15.1          211,200\n Pakistani Female\n                                                                 PR, DR, Cuban Female                           15.7           114,500\n KOREAN                         6.5            11,200\n                                                                 PR, DR, Cuban Female                           14.4           96,600\n Korean Male                    8.0             6,900\n Korean Female                  5.0             4,200\n                                                                 NOTE: Blank cells indicate the estimate is unreliable\n TWO OR MORE                    6.6             4,000\n Two or More Male\n Two or More Female\nFILIPINO                        7.3            23,400\nFilipino Male                   6.5            10,800\nFilipino Female                 8.1            12,700\nHMONG                           14.0            8,300\nHmong Male                      18.6            5,700\nHmong Female\nMAKING THE CONNECTION | Transportation and Youth Disconnection                                                                            39\n"

From the output, it’s clear that a relatively large amount of manipulation will be required to wrangle this data. If you are interested in learning more about this method, please see this case study and this case study.

While not impossible, using the pdftools package in this scenario will be a bit challenging becuase of how the multiple tables are displayed on this page.

While our output may be reproducible, this process may be too time consuming.

Fortunately, there is another way we can proceed to wrangle the data.

We will demonstrate how to produce reproducible tables with image processing software in R using a package called magick which allows for the extraction of text from images. The advantage of this option, is that we can take a screenshot of just a piece of the page to wrangle.

For demonstrative purposes, we will import two sets of data. The first set of data will be used to highlight common errors that the image processing software may produce. The second set of data will be used to demonstrate how to circumvent these errors and produce reproducible datasets efficiently.

Importing with magick

We will now import the data using the magick package which allows for the improtation of images.

First we will take a screenshot of the top part of the gender, race, and ethnicity table on the last page of the 2019 Measure of America Report. We are only interested in the percentage of disconnection across the years, so we dont need our screenshot to include the last couple of columns.

We can show what this file looks like in this rendered rmarkdown website by using the include_graphics() function of the knitr package.

Now, we will use the image_read() function of the magick package to import this image.

We can then use teh image_info() function to make sure that the import worked and to get information about the size, format and color of the image.

# A tibble: 1 x 7
  format width height colorspace matte filesize density
  <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
1 PNG     1086    867 sRGB       TRUE    368488 72x72  

Now let’s take a look at our image in R! Now that we have imported it to see this image, we simply need to type the name of the image.

Nice!

Let’s a couple more images just for fun. Here we will import an image directly from a URL.

Now we will use the image_ocr() function of the magick package to extract the text from the OCS logo image. This function uses the tesseract package which has tools for optical character recognition (OCR), hence the ocr in the function name. This allows the function to identify text in images. These OCR tools have often been developed using machine learning in which an algorithm was trained on images with and without text to “learn” to recognize text. See here to learn more about how OCR works.

[1] "ggplot2\n"

Awesome! We were able to extract text from this hex sticker!

One thing to keep in mind is that this doesn’t always work. Unusual font, angles text, or particular colors can be difficult for the OCR to recoginize.

Here is an example that does not work with the current version of magick:

[1] ""

This is likely do to the background on this particular hex sticker. So sometimes this process requires a bit of trial and error.

Data Wrangling


Now let’s try extracting the text from our image files.

Major Racial and Ethnic Groups

The first image we imported looks like this.

Now we will extract the text!

[1] "United States 12.6 14.7 14.1 13.2 11.7 11.5\nMale 12.3 15.2 14.5 13.3 12.1 11.8\nFemale 12.9 14.1 13.7 13.0 11.2 11.1\nASIAN 7.1 8.5 78 79 6.6 6.6\nAsian Male 6.3 8.3 74 7.2 6.7 6.5\nAsian Female 7.9 8.6 8.1 8.6 6.6 6.7\nWHITE 9.7 11.7 11.2 10.8 9.7 9.4\nWhite Male 9.5 12.3 11.5 10.8 10.0 9.6\nWhite Female 10.0 11.1 10.8 10.7 9.4 9.1\nLATINO 16.7 18.5 17.3 15.2 13.7 13.2\nLatino Male 13.6 16.8 16.0 14.0 12.6 12.4\nLatina Female 20.2 20.3 18.8 16.5 14.8 13.9\nBLACK 20.4 22.5 22.4 20.6 17.2 17.9\nBlack Male 23.7 26.0 25.6 23.5 20.1 20.8\nBlack Female 17.0 19.0 19.3 17.6 14.2 14.8\nNATIVE AMERICAN 24.4 28.8 27.0 26.3 25.8 23.9\nNative American Male 25.0 30.9 28.0 26.9 28.1 23.3\nNative American Female 23.9 26.7 25.9 25.6 23.4 24.5\n"

This looks like it worked fairly well!

We appear to have lost the column names but the values look pretty good.

You may notice that there are lots of \n values in the text from our image. These are newline characters, which denote the end of a line of text and the start of a new line of text.

We can use the str_split() function of the stringr package to split based on the \n characters in the output. We will then unlist the output using the base R unlist() function. By base, we mean that the function it is loaded automatically in an R session. Finally we will use the as_tibble() function of the tibble package to convert the data into tibble format, which is the tidyverse version of a data frame. This will allow us to see the values in the table much better.

To do all of these sequential steps efficiently we will use a method called piping.


Click here if you are unfamiliar with piping in R, which uses this %>% operator.

By piping we mean using the %>% pipe operator which is accessible after loading the tidyverse or several of the packages within the tidyverse like dplyr because they load the magrittr package. This allows us to perform multiple sequential steps on one data input.

# A tibble: 19 x 1
   value                                                 
   <chr>                                                 
 1 "United States 12.6 14.7 14.1 13.2 11.7 11.5"         
 2 "Male 12.3 15.2 14.5 13.3 12.1 11.8"                  
 3 "Female 12.9 14.1 13.7 13.0 11.2 11.1"                
 4 "ASIAN 7.1 8.5 78 79 6.6 6.6"                         
 5 "Asian Male 6.3 8.3 74 7.2 6.7 6.5"                   
 6 "Asian Female 7.9 8.6 8.1 8.6 6.6 6.7"                
 7 "WHITE 9.7 11.7 11.2 10.8 9.7 9.4"                    
 8 "White Male 9.5 12.3 11.5 10.8 10.0 9.6"              
 9 "White Female 10.0 11.1 10.8 10.7 9.4 9.1"            
10 "LATINO 16.7 18.5 17.3 15.2 13.7 13.2"                
11 "Latino Male 13.6 16.8 16.0 14.0 12.6 12.4"           
12 "Latina Female 20.2 20.3 18.8 16.5 14.8 13.9"         
13 "BLACK 20.4 22.5 22.4 20.6 17.2 17.9"                 
14 "Black Male 23.7 26.0 25.6 23.5 20.1 20.8"            
15 "Black Female 17.0 19.0 19.3 17.6 14.2 14.8"          
16 "NATIVE AMERICAN 24.4 28.8 27.0 26.3 25.8 23.9"       
17 "Native American Male 25.0 30.9 28.0 26.9 28.1 23.3"  
18 "Native American Female 23.9 26.7 25.9 25.6 23.4 24.5"
19 ""                                                    

OK, this looks pretty good!

The only issue is that some values appear to be missing a decimal point.

No worries though, we can modify the entire table in a reproducbile way to get those decimal places back. However, first we need to do some other wrangling steps first.

First, let’s spearate the first column about ethnicities with the values in the subsequent columns. We can do so using the separate() function of the tidyr pacakge based on regular expressions. Regular expressions (abbreviated regex) are notation shortcuts that describe patterns in character strings. See here for an RStudio cheetsheat about them.

We want to separate by instances where a letter is followed by a space and then a number.

We can specify any letter by using the regex [:alpha:] notation and any number by using the regex [:digit] notation. We could have listed every letter that we saw the first column ending with like so s|e|E|O|K|N but this would not be as reproducible (meaning maybe this would not work as well next year if a new group were added that ended in a different letter), and we might make a mistake. This is why the regex are so useful.

We can indicate that we want a space by using this regex:

Now to specify that we want to see a letter first followed by a space, followed by a digit, we need to use a look around:

We will use the “preceded by” and “followed by” look arounds. Thus (?<=[:alpha:]) stands for any letter that appears before a space \\s that is followed by any digit (?=[0-9]). Altogether the pattern we want to separate by looks like this: "(?<=[:alpha:])\\s(?=[0-9])".

Now to separate the value column into two cloumns, we can use the separate function of the tidyr pacakge to do this. This will allow us to not only split the rows by our regex expression, but also to create column names.

There are three important arguments for the seperate() function:
- col - this specifies what column you are separating
- into - this specifies the names of the new columns you are creating
- sep - this specifies what character string to look for to separate by

Thus we will separate the value column into Group and years columns.

# A tibble: 19 x 2
   Group                    Years                        
   <chr>                    <chr>                        
 1 "United States"          12.6 14.7 14.1 13.2 11.7 11.5
 2 "Male"                   12.3 15.2 14.5 13.3 12.1 11.8
 3 "Female"                 12.9 14.1 13.7 13.0 11.2 11.1
 4 "ASIAN"                  7.1 8.5 78 79 6.6 6.6        
 5 "Asian Male"             6.3 8.3 74 7.2 6.7 6.5       
 6 "Asian Female"           7.9 8.6 8.1 8.6 6.6 6.7      
 7 "WHITE"                  9.7 11.7 11.2 10.8 9.7 9.4   
 8 "White Male"             9.5 12.3 11.5 10.8 10.0 9.6  
 9 "White Female"           10.0 11.1 10.8 10.7 9.4 9.1  
10 "LATINO"                 16.7 18.5 17.3 15.2 13.7 13.2
11 "Latino Male"            13.6 16.8 16.0 14.0 12.6 12.4
12 "Latina Female"          20.2 20.3 18.8 16.5 14.8 13.9
13 "BLACK"                  20.4 22.5 22.4 20.6 17.2 17.9
14 "Black Male"             23.7 26.0 25.6 23.5 20.1 20.8
15 "Black Female"           17.0 19.0 19.3 17.6 14.2 14.8
16 "NATIVE AMERICAN"        24.4 28.8 27.0 26.3 25.8 23.9
17 "Native American Male"   25.0 30.9 28.0 26.9 28.1 23.3
18 "Native American Female" 23.9 26.7 25.9 25.6 23.4 24.5
19 ""                       <NA>                         

Looks good!

Let’s also get rid of the all caps for the major categories of the Group column. We can convert the words to only capitalize the first letter using the str_to_title() function of the stringr package. To specifically modify the Group column we can use the mutate function of the dplyr package.

We are also going to use a special pipe operator from the magrittr package called the compound assignment pipe-operator or sometimes the double pipe operator.

This allows us to use the major_groups as our input and reassign it at the end after all the subsequent steps have been performed, although in this case it is only one step.

# A tibble: 19 x 2
   Group                    Years                        
   <chr>                    <chr>                        
 1 "United States"          12.6 14.7 14.1 13.2 11.7 11.5
 2 "Male"                   12.3 15.2 14.5 13.3 12.1 11.8
 3 "Female"                 12.9 14.1 13.7 13.0 11.2 11.1
 4 "Asian"                  7.1 8.5 78 79 6.6 6.6        
 5 "Asian Male"             6.3 8.3 74 7.2 6.7 6.5       
 6 "Asian Female"           7.9 8.6 8.1 8.6 6.6 6.7      
 7 "White"                  9.7 11.7 11.2 10.8 9.7 9.4   
 8 "White Male"             9.5 12.3 11.5 10.8 10.0 9.6  
 9 "White Female"           10.0 11.1 10.8 10.7 9.4 9.1  
10 "Latino"                 16.7 18.5 17.3 15.2 13.7 13.2
11 "Latino Male"            13.6 16.8 16.0 14.0 12.6 12.4
12 "Latina Female"          20.2 20.3 18.8 16.5 14.8 13.9
13 "Black"                  20.4 22.5 22.4 20.6 17.2 17.9
14 "Black Male"             23.7 26.0 25.6 23.5 20.1 20.8
15 "Black Female"           17.0 19.0 19.3 17.6 14.2 14.8
16 "Native American"        24.4 28.8 27.0 26.3 25.8 23.9
17 "Native American Male"   25.0 30.9 28.0 26.9 28.1 23.3
18 "Native American Female" 23.9 26.7 25.9 25.6 23.4 24.5
19 ""                       <NA>                         

Nice! That looks better.

For the year data we would like to try splitting the strings for each row into different columns based on a space. Currently all the data is listed in one column called Years.

We can use the separate function of the tidyr pacakge again to do this. This will allow us to split the rows by spaces, as well as provide names for the new columns.

# A tibble: 19 x 7
   Group                    `2008` `2010` `2012` `2014` `2016` `2017`
   <chr>                    <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
 1 "United States"          12.6   14.7   14.1   13.2   11.7   11.5  
 2 "Male"                   12.3   15.2   14.5   13.3   12.1   11.8  
 3 "Female"                 12.9   14.1   13.7   13.0   11.2   11.1  
 4 "Asian"                  7.1    8.5    78     79     6.6    6.6   
 5 "Asian Male"             6.3    8.3    74     7.2    6.7    6.5   
 6 "Asian Female"           7.9    8.6    8.1    8.6    6.6    6.7   
 7 "White"                  9.7    11.7   11.2   10.8   9.7    9.4   
 8 "White Male"             9.5    12.3   11.5   10.8   10.0   9.6   
 9 "White Female"           10.0   11.1   10.8   10.7   9.4    9.1   
10 "Latino"                 16.7   18.5   17.3   15.2   13.7   13.2  
11 "Latino Male"            13.6   16.8   16.0   14.0   12.6   12.4  
12 "Latina Female"          20.2   20.3   18.8   16.5   14.8   13.9  
13 "Black"                  20.4   22.5   22.4   20.6   17.2   17.9  
14 "Black Male"             23.7   26.0   25.6   23.5   20.1   20.8  
15 "Black Female"           17.0   19.0   19.3   17.6   14.2   14.8  
16 "Native American"        24.4   28.8   27.0   26.3   25.8   23.9  
17 "Native American Male"   25.0   30.9   28.0   26.9   28.1   23.3  
18 "Native American Female" 23.9   26.7   25.9   25.6   23.4   24.5  
19 ""                       <NA>   <NA>   <NA>   <NA>   <NA>   <NA>  

Looks pretty good!

We appear to have an empty row at the very end. Since all the values are NA, we can use the drop_na() function of the tidyr package to remove it.

# A tibble: 18 x 7
   Group                  `2008` `2010` `2012` `2014` `2016` `2017`
   <chr>                  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
 1 United States          12.6   14.7   14.1   13.2   11.7   11.5  
 2 Male                   12.3   15.2   14.5   13.3   12.1   11.8  
 3 Female                 12.9   14.1   13.7   13.0   11.2   11.1  
 4 Asian                  7.1    8.5    78     79     6.6    6.6   
 5 Asian Male             6.3    8.3    74     7.2    6.7    6.5   
 6 Asian Female           7.9    8.6    8.1    8.6    6.6    6.7   
 7 White                  9.7    11.7   11.2   10.8   9.7    9.4   
 8 White Male             9.5    12.3   11.5   10.8   10.0   9.6   
 9 White Female           10.0   11.1   10.8   10.7   9.4    9.1   
10 Latino                 16.7   18.5   17.3   15.2   13.7   13.2  
11 Latino Male            13.6   16.8   16.0   14.0   12.6   12.4  
12 Latina Female          20.2   20.3   18.8   16.5   14.8   13.9  
13 Black                  20.4   22.5   22.4   20.6   17.2   17.9  
14 Black Male             23.7   26.0   25.6   23.5   20.1   20.8  
15 Black Female           17.0   19.0   19.3   17.6   14.2   14.8  
16 Native American        24.4   28.8   27.0   26.3   25.8   23.9  
17 Native American Male   25.0   30.9   28.0   26.9   28.1   23.3  
18 Native American Female 23.9   26.7   25.9   25.6   23.4   24.5  

Great, now we have 18 rows.

It’s important to look very carefully at the text. Again, there are some values missing a decimal place. For example the row where the Group vlaue is Asian, the third and fourth values are missing a decimal place.

Looking at the orginal table we see that even values like 10 are represented as 10.0.

So, to fix this we will remove all decimals (which is sort of like multiplying all values that do have a decimal by 10) and then we will multiply all values by .01 to add the decimals back. We will use the mutate() function combined with the across() function which allows us to specify which columns we want to perform a function on. We want to do this to all the year columns, so we can exclude the Group column by using a minus sign - in the .cols argument of the across() function like so: mutate(across(.cols = -Group))

Finally, we will use the str_remove() function of the stringr package to find instances of “.” and remove them. Since “.” is a regex, and indicates any character string, thus we need “\” to have R interpret a decimal or a period instead, as we can see from the RStudio cheetsheat:

To pass the data from all the coulumns except our Group variable into our str_remove() function, we need to use the . notation as a replacement for the data that we specified by the .colsargument and we need to use ~ in front of the function name.

# A tibble: 18 x 7
   Group                  `2008` `2010` `2012` `2014` `2016` `2017`
   <chr>                  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
 1 United States          126    147    141    132    117    115   
 2 Male                   123    152    145    133    121    118   
 3 Female                 129    141    137    130    112    111   
 4 Asian                  71     85     78     79     66     66    
 5 Asian Male             63     83     74     72     67     65    
 6 Asian Female           79     86     81     86     66     67    
 7 White                  97     117    112    108    97     94    
 8 White Male             95     123    115    108    100    96    
 9 White Female           100    111    108    107    94     91    
10 Latino                 167    185    173    152    137    132   
11 Latino Male            136    168    160    140    126    124   
12 Latina Female          202    203    188    165    148    139   
13 Black                  204    225    224    206    172    179   
14 Black Male             237    260    256    235    201    208   
15 Black Female           170    190    193    176    142    148   
16 Native American        244    288    270    263    258    239   
17 Native American Male   250    309    280    269    281    233   
18 Native American Female 239    267    259    256    234    245   

Great, now in order to multiply each value by 0.1 we need to first make the values numeric. Currently we can tell that they are character strings based on the <char> values listed under each column name.

Click here for an explanation about data types in R and about character strings.

There are several classes of data in R programming. Character is one of these classes. A character string is an individual data value made up of characters. This can be a paragraph, like the legend for the table, or it can be a single letter or number like the letter "a" or the number "3". If data are of class character, than the numeric values will not be processed like a numeric value in a mathematical sense. If you want your numeric values to be interpreted that way, they need to be converted to a numeric class. The options typically used are integer (which has no decimal place) and double precision (which has a decimal place).

To convert our values to be numeric we can use the base as.numeric() function. Again we will use mutate() and across(). Since this function doesn’t require any arguments, we don’t need to specify it’s input like we just did for the str_remove() but we could do so as shown below.

# A tibble: 18 x 7
   Group                  `2008` `2010` `2012` `2014` `2016` `2017`
   <chr>                   <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
 1 United States             126    147    141    132    117    115
 2 Male                      123    152    145    133    121    118
 3 Female                    129    141    137    130    112    111
 4 Asian                      71     85     78     79     66     66
 5 Asian Male                 63     83     74     72     67     65
 6 Asian Female               79     86     81     86     66     67
 7 White                      97    117    112    108     97     94
 8 White Male                 95    123    115    108    100     96
 9 White Female              100    111    108    107     94     91
10 Latino                    167    185    173    152    137    132
11 Latino Male               136    168    160    140    126    124
12 Latina Female             202    203    188    165    148    139
13 Black                     204    225    224    206    172    179
14 Black Male                237    260    256    235    201    208
15 Black Female              170    190    193    176    142    148
16 Native American           244    288    270    263    258    239
17 Native American Male      250    309    280    269    281    233
18 Native American Female    239    267    259    256    234    245

Great, we can see that the year variables are now numeric as they are now type double as indicated by the <dbl> below each column name. See the above section about data types if you are unfamiliar with type double.

OK, now we can multiply each value by 0.1 to add our decimal points back and get back to the orginal values.

# A tibble: 18 x 7
   Group                  `2008` `2010` `2012` `2014` `2016` `2017`
   <chr>                   <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
 1 United States            12.6   14.7   14.1   13.2   11.7   11.5
 2 Male                     12.3   15.2   14.5   13.3   12.1   11.8
 3 Female                   12.9   14.1   13.7   13     11.2   11.1
 4 Asian                     7.1    8.5    7.8    7.9    6.6    6.6
 5 Asian Male                6.3    8.3    7.4    7.2    6.7    6.5
 6 Asian Female              7.9    8.6    8.1    8.6    6.6    6.7
 7 White                     9.7   11.7   11.2   10.8    9.7    9.4
 8 White Male                9.5   12.3   11.5   10.8   10      9.6
 9 White Female             10     11.1   10.8   10.7    9.4    9.1
10 Latino                   16.7   18.5   17.3   15.2   13.7   13.2
11 Latino Male              13.6   16.8   16     14     12.6   12.4
12 Latina Female            20.2   20.3   18.8   16.5   14.8   13.9
13 Black                    20.4   22.5   22.4   20.6   17.2   17.9
14 Black Male               23.7   26     25.6   23.5   20.1   20.8
15 Black Female             17     19     19.3   17.6   14.2   14.8
16 Native American          24.4   28.8   27     26.3   25.8   23.9
17 Native American Male     25     30.9   28     26.9   28.1   23.3
18 Native American Female   23.9   26.7   25.9   25.6   23.4   24.5

Now is a good time to double check that our table looks like what we expect.

Looks good!

We also want to add a couple of variables about Race_Ethnicity and Gender so that we can select across groups later. We can use the recode() function of the dplyr package to change specific values, as we create a new Race_Ethnicity variable from the Group variable. For the Data for all of the US we want the Race_Ethnicity variable values to be "All_races".

# A tibble: 6 x 8
  Group         `2008` `2010` `2012` `2014` `2016` `2017` Race_Ethnicity
  <chr>          <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl> <chr>         
1 United States   12.6   14.7   14.1   13.2   11.7   11.5 All_races     
2 Male            12.3   15.2   14.5   13.3   12.1   11.8 All_races     
3 Female          12.9   14.1   13.7   13     11.2   11.1 All_races     
4 Asian            7.1    8.5    7.8    7.9    6.6    6.6 Asian         
5 Asian Male       6.3    8.3    7.4    7.2    6.7    6.5 Asian Male    
6 Asian Female     7.9    8.6    8.1    8.6    6.6    6.7 Asian Female  

We also want to remove Male and Female from this “Race_Ethnicity” variable, We can do so using the str_remove() function of the stringr package. Importantly, we are also removing the space beore “Female” and "Male.

# A tibble: 6 x 8
  Group         `2008` `2010` `2012` `2014` `2016` `2017` Race_Ethnicity
  <chr>          <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl> <chr>         
1 United States   12.6   14.7   14.1   13.2   11.7   11.5 All_races     
2 Male            12.3   15.2   14.5   13.3   12.1   11.8 All_races     
3 Female          12.9   14.1   13.7   13     11.2   11.1 All_races     
4 Asian            7.1    8.5    7.8    7.9    6.6    6.6 Asian         
5 Asian Male       6.3    8.3    7.4    7.2    6.7    6.5 Asian         
6 Asian Female     7.9    8.6    8.1    8.6    6.6    6.7 Asian         

For the new Gender variable we would like to extract just the “Female” and “Male” text from the Group variable. The str_extract() function of the stringr package will do this, and it will give us an NA value for any rows whhere “Female” or “Male” were not present. We can then replace the NA values with the text “All” to represent the total value for both male and female using the replace_na() function of the tidyr() package.

# A tibble: 6 x 9
  Group         `2008` `2010` `2012` `2014` `2016` `2017` Race_Ethnicity Gender
  <chr>          <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl> <chr>          <chr> 
1 United States   12.6   14.7   14.1   13.2   11.7   11.5 All_races      All   
2 Male            12.3   15.2   14.5   13.3   12.1   11.8 All_races      Male  
3 Female          12.9   14.1   13.7   13     11.2   11.1 All_races      Female
4 Asian            7.1    8.5    7.8    7.9    6.6    6.6 Asian          All   
5 Asian Male       6.3    8.3    7.4    7.2    6.7    6.5 Asian          Male  
6 Asian Female     7.9    8.6    8.1    8.6    6.6    6.7 Asian          Female

We would also like to replace Latino and Latina with Latinx. We can use another string_r function for this. This function, str_replace() allows us to remove and replace a particular pattern.

Question Opportunity

Why is the str_replace() function in this case a better option than using the recode() function?

# A tibble: 18 x 9
   Group         `2008` `2010` `2012` `2014` `2016` `2017` Race_Ethnicity Gender
   <chr>          <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl> <chr>          <chr> 
 1 United States   12.6   14.7   14.1   13.2   11.7   11.5 All_races      All   
 2 Male            12.3   15.2   14.5   13.3   12.1   11.8 All_races      Male  
 3 Female          12.9   14.1   13.7   13     11.2   11.1 All_races      Female
 4 Asian            7.1    8.5    7.8    7.9    6.6    6.6 Asian          All   
 5 Asian Male       6.3    8.3    7.4    7.2    6.7    6.5 Asian          Male  
 6 Asian Female     7.9    8.6    8.1    8.6    6.6    6.7 Asian          Female
 7 White            9.7   11.7   11.2   10.8    9.7    9.4 White          All   
 8 White Male       9.5   12.3   11.5   10.8   10      9.6 White          Male  
 9 White Female    10     11.1   10.8   10.7    9.4    9.1 White          Female
10 Latinx          16.7   18.5   17.3   15.2   13.7   13.2 Latinx         All   
11 Latinx Male     13.6   16.8   16     14     12.6   12.4 Latinx         Male  
12 Latinx Female   20.2   20.3   18.8   16.5   14.8   13.9 Latinx         Female
13 Black           20.4   22.5   22.4   20.6   17.2   17.9 Black          All   
14 Black Male      23.7   26     25.6   23.5   20.1   20.8 Black          Male  
15 Black Female    17     19     19.3   17.6   14.2   14.8 Black          Female
16 Native Ameri…   24.4   28.8   27     26.3   25.8   23.9 Native Americ… All   
17 Native Ameri…   25     30.9   28     26.9   28.1   23.3 Native Americ… Male  
18 Native Ameri…   23.9   26.7   25.9   25.6   23.4   24.5 Native Americ… Female

Finally, we would like to change the shape of our table so that we have a new column that represents the year and a new column that represents the value for that year.

To do so we will be making our table “longer”, meaning that it will have fewer columns and more rows. See here for more information about different table formats, typically referred to as wide and long or sometimes narrow.

We will use the pivot_longer() function of the tidyr package to change the shape of our table.

There are 3 main arguments in this function:

  1. cols - which specifies what columns to collapse
  2. names_to - which specifies the name of the new column that will be created that will contain the column names of the columns you are collapsing
  3. values_to - which specifies the name of the new column that will be created that will contain the values from the columns you are collapsing

To specify that we want to collapse all the columns that have year values, we can chose those that contain the string "20" using the contains() function of dplyr.

# A tibble: 108 x 5
   Group         Race_Ethnicity Gender  Year Percent
   <chr>         <chr>          <chr>  <dbl>   <dbl>
 1 United States All_races      All     2008    12.6
 2 United States All_races      All     2010    14.7
 3 United States All_races      All     2012    14.1
 4 United States All_races      All     2014    13.2
 5 United States All_races      All     2016    11.7
 6 United States All_races      All     2017    11.5
 7 Male          All_races      Male    2008    12.3
 8 Male          All_races      Male    2010    15.2
 9 Male          All_races      Male    2012    14.5
10 Male          All_races      Male    2014    13.3
# … with 98 more rows

Excellent, now we need to do the same for the other two tables on this page:

Asian Subgroups 2017

Now let’s do the same for the Asian subgroups table.

First we will start by importing a screenshot for this table without the header, as we did before. The name of the file for the screenshot is asian_subgroups.png and it is located in the img directory.

Question Opportunity

Can you recall the command to import an image into R using the magick package?

Question Opportunity

Can you recall the command to extract the text from an image using the magick package?

Click here to reveal the code.

[1] "United States 11.5\nMale 11.8\nFemale 11.1\nASIAN 6.8\nAsian Male 65\nAsian Female 67\nCHINESE 43\nChinese Male AT\nChinese Female 3.9\nVIETNAMESE 5.5\nVietnamese Male 75\nVietnamese Female 3.4\nINDIAN 5.9\nIndian Male 4.1\nIndian Female 78\nPAKISTANI 64\nPakistani Male\n\nPakistani Female\n\nKOREAN 65\nKorean Male 8.0\nKorean Female 5.0\nTWO OR MORE 68\nTwo or More Male\n\nTwo or More Female\nFILIPINO. S™S™~SS\nFilipino Male 65\nFilipino Female 81\nHMONG 14.0\nHmong Male 18.6\n"

Now we again want to split the data into rows based on the newline regex. This is something we will continue to do for all the tables.

One option is to copy and paste code we wrote above each time. However, this is not very efficient and is error prone. Alternatively, we can create a R function to accomplish this succinctly. Functions allow us to perform the same process on multiple data inputs. See this other case study for more details about how to write a function.

In general, the process of writing functions involves first specifying an input that is used within the function to create an output. In this case, the data input is text which will be replaced by the actual image text that we are working on, and then used in the subsequent steps to wrangle the data. We will call our function make_rows().

Great! Now let’s apply our function to the asian_subgroups data!

# A tibble: 33 x 1
   value             
   <chr>             
 1 United States 11.5
 2 Male 11.8         
 3 Female 11.1       
 4 ASIAN 6.8         
 5 Asian Male 65     
 6 Asian Female 67   
 7 CHINESE 43        
 8 Chinese Male AT   
 9 Chinese Female 3.9
10 VIETNAMESE 5.5    
# … with 23 more rows

As you can see, there are some strange values for some of the rows. For example the row that starts with CHINESE MAle has AT percentage of disconnected youth, and the row that should say FILIPINO says S™S™~SS.

[[1]]
[1] "Chinese" "Male"    "AT"     
[[1]]
[1] "FILIPINO." "S™S™~SS"  

The rows with no values are possibly causing this issue. According to the PDF, these spaces are empty to denote that the estimates were unreliable for these groups.

So we will now import and extract text from three screenshots of this table where we stop just after the row that starts with PAKISTANI in the first image, and then an image of the Korean rows up to the next row with no values, and finally an image starting at the row that starts with FILIPNO.

# A tibble: 17 x 1
   value                  
   <chr>                  
 1 "United States 11.5"   
 2 "Male 11.8"            
 3 "Female 11.1"          
 4 "ASIAN 6.6"            
 5 "Asian Male 6.5"       
 6 "Asian Female 6.7"     
 7 "CHINESE 4.3"          
 8 "Chinese Male 4.7"     
 9 "Chinese Female 3.9"   
10 "VIETNAMESE 5.5"       
11 "Vietnamese Male 7.5"  
12 "Vietnamese Female 3.4"
13 "INDIAN 5.9"           
14 "Indian Male 4.1"      
15 "Indian Female 7.8"    
16 "PAKISTANI 6.4"        
17 ""                     
# A tibble: 5 x 1
  value              
  <chr>              
1 "KOREAN 6.5"       
2 "Korean Male 8.0"  
3 "Korean Female 5.0"
4 "TWO OR MORE 6.6"  
5 ""                 
# A tibble: 6 x 1
  value                
  <chr>                
1 "FILIPINO 7.3"       
2 "Filipino Male 6.5"  
3 "Filipino Female 8.1"
4 "HMONG 14.0"         
5 "Hmong Male 18.6"    
6 ""                   

Much better!

We can now combine the objects with the bind_rows() function of the dplyr package, which will append each of these tibbles together one after the other.

# A tibble: 28 x 1
   value             
   <chr>             
 1 United States 11.5
 2 Male 11.8         
 3 Female 11.1       
 4 ASIAN 6.6         
 5 Asian Male 6.5    
 6 Asian Female 6.7  
 7 CHINESE 4.3       
 8 Chinese Male 4.7  
 9 Chinese Female 3.9
10 VIETNAMESE 5.5    
# … with 18 more rows

Looks pretty good!

Now we have similar wrangling steps to perform as we did previously and we will need to do the same for the Latinx subgroups table. So it is a good idea to make another function.

Even though we appear to have all of the decimal places for the values, we will include this in our function, just to make sure the data is correct.

Question Opportunity

Can you explain what each of the commands are doing within the function?

Question Opportunity

Why do we not need to use pivot_longer() with this data?

Latinx Subgroups 2017

Recall that this is the table we want to wrangle:

Question Opportunity

Do you notice anything incorrect about this table?

Sometimes when wrangling text data, we will come across a typo. We need to determine how to respond to the typo and make note of it. It’s often best to consult a secondary source to confirm that changes made are accurate.

For the purposes of this case study, we will assume that the first of the two rows represents male disconnection rates in the Latino/a subgroup; this would be consistent with the ordering of genders in the previous subgroups.

We will make sure to correct this typo when we can.

After trial and error, two screenshots were determined best for importing this data. The names of the files for the screenshots are latinx_sub_A.png and "latinx_sub_B.png. They are located in the img directory.

Question Opportunity

Can you recall the commands to import and extract the data?

Click here to reveal the code.

[1] "LATINO 13.2\nLatino Male 12.4\nLatina Female 13.9\n"

[1] "SOUTH AMERICAN 8.4\nSouth American Male 9.1\nSouth American Female 7.7\nCENTRAL AMERICAN 12.0\nCentral American Male 9.3\nCentral American Female 15.0\nMEXICAN 13.3\nMexican Male 12.2\nMexican Female 14.4\nOTHER LATINO 13.6\nOther Latino Male 15.3\nOther Latina Female 11.5\n"

[1] "PUERTO RICAN, DOMINICAN, CUBAN 15.1\nPR, DR, Cuban Female 15.7\nPR, DR, Cuban Female 14.4\n"

We can combine the strings together using the str_c() function (wich stands for string collapse) of the stringr package.

[1] "LATINO 13.2\nLatino Male 12.4\nLatina Female 13.9\nSOUTH AMERICAN 8.4\nSouth American Male 9.1\nSouth American Female 7.7\nCENTRAL AMERICAN 12.0\nCentral American Male 9.3\nCentral American Female 15.0\nMEXICAN 13.3\nMexican Male 12.2\nMexican Female 14.4\nOTHER LATINO 13.6\nOther Latino Male 15.3\nOther Latina Female 11.5\nPUERTO RICAN, DOMINICAN, CUBAN 15.1\nPR, DR, Cuban Female 15.7\nPR, DR, Cuban Female 14.4\n"

Now let’s correct that typo.

Question Opportunity

How might you do this?

Click here to reveal the code.

[1] "LATINO 13.2\nLatino Male 12.4\nLatina Female 13.9\nSOUTH AMERICAN 8.4\nSouth American Male 9.1\nSouth American Female 7.7\nCENTRAL AMERICAN 12.0\nCentral American Male 9.3\nCentral American Female 15.0\nMEXICAN 13.3\nMexican Male 12.2\nMexican Female 14.4\nOTHER LATINO 13.6\nOther Latino Male 15.3\nOther Latina Female 11.5\nPUERTO RICAN, DOMINICAN, CUBAN 15.1\nPR, DR, Cuban Male 15.7\nPR, DR, Cuban Female 14.4\n"

Question Opportunity

Can you recall the commands within our make_rows() function to separate the data into rows and create a tibble?

Click here to reveal the code.

# A tibble: 19 x 1
   value                                
   <chr>                                
 1 "LATINO 13.2"                        
 2 "Latino Male 12.4"                   
 3 "Latina Female 13.9"                 
 4 "SOUTH AMERICAN 8.4"                 
 5 "South American Male 9.1"            
 6 "South American Female 7.7"          
 7 "CENTRAL AMERICAN 12.0"              
 8 "Central American Male 9.3"          
 9 "Central American Female 15.0"       
10 "MEXICAN 13.3"                       
11 "Mexican Male 12.2"                  
12 "Mexican Female 14.4"                
13 "OTHER LATINO 13.6"                  
14 "Other Latino Male 15.3"             
15 "Other Latina Female 11.5"           
16 "PUERTO RICAN, DOMINICAN, CUBAN 15.1"
17 "PR, DR, Cuban Male 15.7"            
18 "PR, DR, Cuban Female 14.4"          
19 ""                                   

Now we can apply our function.

# A tibble: 18 x 4
   Group                          Percent Race_Ethnicity                 Gender
   <chr>                            <dbl> <chr>                          <chr> 
 1 Latino                            13.2 Latino                         All   
 2 Latino Male                       12.4 Latino                         Male  
 3 Latina Female                     13.9 Latina                         Female
 4 South American                     8.4 South American                 All   
 5 South American Male                9.1 South American                 Male  
 6 South American Female              7.7 South American                 Female
 7 Central American                  12   Central American               All   
 8 Central American Male              9.3 Central American               Male  
 9 Central American Female           15   Central American               Female
10 Mexican                           13.3 Mexican                        All   
11 Mexican Male                      12.2 Mexican                        Male  
12 Mexican Female                    14.4 Mexican                        Female
13 Other Latino                      13.6 Other Latino                   All   
14 Other Latino Male                 15.3 Other Latino                   Male  
15 Other Latina Female               11.5 Other Latina                   Female
16 Puerto Rican, Dominican, Cuban    15.1 Puerto Rican, Dominican, Cuban All   
17 Pr, Dr, Cuban Male                15.7 Pr, Dr, Cuban                  Male  
18 Pr, Dr, Cuban Female              14.4 Pr, Dr, Cuban                  Female

It looks like we’ve succesfully corrected the typo!

Let’s also replace the abbreviations for Puerto Rican and Domincan and let’s replace Latino/Latina with Latinx.

Question Opportunity

How might you do this?

Click here to reveal the code.

# A tibble: 18 x 4
   Group                             Percent Race_Ethnicity               Gender
   <chr>                               <dbl> <chr>                        <chr> 
 1 Latinx                               13.2 Latinx                       All   
 2 Latinx Male                          12.4 Latinx                       Male  
 3 Latinx Female                        13.9 Latinx                       Female
 4 South American                        8.4 South American               All   
 5 South American Male                   9.1 South American               Male  
 6 South American Female                 7.7 South American               Female
 7 Central American                     12   Central American             All   
 8 Central American Male                 9.3 Central American             Male  
 9 Central American Female              15   Central American             Female
10 Mexican                              13.3 Mexican                      All   
11 Mexican Male                         12.2 Mexican                      Male  
12 Mexican Female                       14.4 Mexican                      Female
13 Other Latinx                         13.6 Other Latinx                 All   
14 Other Latinx Male                    15.3 Other Latinx                 Male  
15 Other Latinx Female                  11.5 Other Latinx                 Female
16 Puerto Rican, Dominican, Cuban       15.1 Puerto Rican, Dominican, Cu… All   
17 Puerto Rican, Dominican, Cuban M…    15.7 Puerto Rican, Dominican, Cu… Male  
18 Puerto Rican, Dominican, Cuban F…    14.4 Puerto Rican, Dominican, Cu… Female

Great!

Now we are ready to look at the data from 2018 for the Asian and Latinx subgroups from the other report.

Asian Subgroups 2018

Recall that this was the page with the table of interest for the asian subgroups with 2018 data:

As you can see, the data for the subgroups is shown in the table but the overall data for Asians is located in the text.

We will use a screenshot of each to extract the data for this year.

Trial and error indicated that again dividing the table into multiple screenshots improved the text extraction:

# A tibble: 23 x 1
   value         
   <chr>         
 1 "CHINESE : 41"
 2 "Men 4.5"     
 3 "Women : 3.7" 
 4 ""            
 5 "INDIAN 5.4"  
 6 "Men 4.7"     
 7 "Women : 6.1" 
 8 ""            
 9 "KOREAN : 5.5"
10 "Men 5.6"     
# … with 13 more rows

Now we need to modify our function a bit for this new data.

Firstly, we now have colons : in our table that we will want to separate by. Unfortunately, the text in each row isn’t extracted in the same way by the OCR.Thus some rows have only a space, while others have spaces around a colon; or for the row with VIETNAM we see a colon directly after the word followed by a space. Thus we will modify our seperate() function with this change. We can specify that the separator between any letter and any digit should be either a space (\\s) or a colon with a space before and after it (\\s:\\s) using the or (|)opperator.

So this will look like this:

# A tibble: 23 x 2
   Group     Percent
   <chr>     <chr>  
 1 "CHINESE" 41     
 2 "Men"     4.5    
 3 "Women"   3.7    
 4 ""        <NA>   
 5 "INDIAN"  5.4    
 6 "Men"     4.7    
 7 "Women"   6.1    
 8 ""        <NA>   
 9 "KOREAN"  5.5    
10 "Men"     5.6    
# … with 13 more rows

Then because of the row with VIETNAM, we will want to remove this colon using the str_remove() function like this:

The other difference from the previous function, is that we want to fill in a new Race_Ethnicity variable with the previous rows. We can do so by first replacing “Men” or “Women” which with the or operator is (“Men|Women”), with “missing”. Then we need to convert these to NA values using the na_if() function of the dplyr package, we just need to specify what column to modify and what value to change to NA. Finally we will then repace the NA values with the previous non-NA value using the fill() function of the tidyr package. Note that this does not work inside of the mutate() function. We just need to simply specify what column to modify and then the direction to replace values. In this case we want to replace in the downward direction using the previous values.

This will look like this:

# A tibble: 6 x 3
  Group     Percent Race_Ethnicity
  <chr>     <chr>   <chr>         
1 "CHINESE" 41      "CHINESE"     
2 "Men"     4.5     "missing"     
3 "Women"   3.7     "missing"     
4 ""        <NA>    ""            
5 "INDIAN"  5.4     "INDIAN"      
6 "Men"     4.7     "missing"     
# A tibble: 6 x 3
  Group     Percent Race_Ethnicity
  <chr>     <chr>   <chr>         
1 "CHINESE" 41      "CHINESE"     
2 "Men"     4.5      <NA>         
3 "Women"   3.7      <NA>         
4 ""        <NA>    ""            
5 "INDIAN"  5.4     "INDIAN"      
6 "Men"     4.7      <NA>         
# A tibble: 6 x 3
  Group     Percent Race_Ethnicity
  <chr>     <chr>   <chr>         
1 "CHINESE" 41      "CHINESE"     
2 "Men"     4.5     "CHINESE"     
3 "Women"   3.7     "CHINESE"     
4 ""        <NA>    ""            
5 "INDIAN"  5.4     "INDIAN"      
6 "Men"     4.7     "INDIAN"      

OK! Now, let’s combine these pieces of our new function with the old pieces:

# A tibble: 17 x 4
   Group      Percent Race_Ethnicity Gender
   <chr>        <dbl> <chr>          <chr> 
 1 Chinese        4.1 Chinese        All   
 2 Men            4.5 Chinese        Men   
 3 Women          3.7 Chinese        Women 
 4 Indian         5.4 Indian         All   
 5 Men            4.7 Indian         Men   
 6 Women          6.1 Indian         Women 
 7 Korean         5.5 Korean         All   
 8 Men            5.6 Korean         Men   
 9 Women          5.4 Korean         Women 
10 Vietnamese     6.3 Vietnamese     All   
11 Men            7.6 Vietnamese     Men   
12 Women          5   Vietnamese     Women 
13 Filipino       6.8 Filipino       All   
14 Men            6.3 Filipino       Men   
15 Women          7.4 Filipino       Women 
16 Hmong         10.2 Hmong          All   
17 Cambodian     13.8 Cambodian      All   

Looking good!

Now we just need to add the data for all Asians from the text.

We can do this using the add_row() function of the dplyr() package.

# A tibble: 20 x 4
   Group      Percent Race_Ethnicity Gender
   <chr>        <dbl> <chr>          <chr> 
 1 Chinese        4.1 Chinese        All   
 2 Men            4.5 Chinese        Men   
 3 Women          3.7 Chinese        Women 
 4 Indian         5.4 Indian         All   
 5 Men            4.7 Indian         Men   
 6 Women          6.1 Indian         Women 
 7 Korean         5.5 Korean         All   
 8 Men            5.6 Korean         Men   
 9 Women          5.4 Korean         Women 
10 Vietnamese     6.3 Vietnamese     All   
11 Men            7.6 Vietnamese     Men   
12 Women          5   Vietnamese     Women 
13 Filipino       6.8 Filipino       All   
14 Men            6.3 Filipino       Men   
15 Women          7.4 Filipino       Women 
16 Hmong         10.2 Hmong          All   
17 Cambodian     13.8 Cambodian      All   
18 Asian          6.2 Asian          All   
19 Asian          6.4 Asian          Men   
20 Asian          6.1 Asian          Women 

OK, now we just want to combine the 2018 data and the 2017 data for the asian subgroups.

First let’s add a varaible for year to both. Using mutate() we can add a variable Year where all values are 2017 like so:

# A tibble: 25 x 5
   Group          Percent Race_Ethnicity Gender  Year
   <chr>            <dbl> <chr>          <chr>  <dbl>
 1 United States     11.5 All_races      All     2017
 2 Male              11.8 All_races      Male    2017
 3 Female            11.1 All_races      Female  2017
 4 Asian              6.6 Asian          All     2017
 5 Asian Male         6.5 Asian          Male    2017
 6 Asian Female       6.7 Asian          Female  2017
 7 Chinese            4.3 Chinese        All     2017
 8 Chinese Male       4.7 Chinese        Male    2017
 9 Chinese Female     3.9 Chinese        Female  2017
10 Vietnamese         5.5 Vietnamese     All     2017
# … with 15 more rows
# A tibble: 20 x 5
   Group      Percent Race_Ethnicity Gender  Year
   <chr>        <dbl> <chr>          <chr>  <dbl>
 1 Chinese        4.1 Chinese        All     2018
 2 Men            4.5 Chinese        Men     2018
 3 Women          3.7 Chinese        Women   2018
 4 Indian         5.4 Indian         All     2018
 5 Men            4.7 Indian         Men     2018
 6 Women          6.1 Indian         Women   2018
 7 Korean         5.5 Korean         All     2018
 8 Men            5.6 Korean         Men     2018
 9 Women          5.4 Korean         Women   2018
10 Vietnamese     6.3 Vietnamese     All     2018
11 Men            7.6 Vietnamese     Men     2018
12 Women          5   Vietnamese     Women   2018
13 Filipino       6.8 Filipino       All     2018
14 Men            6.3 Filipino       Men     2018
15 Women          7.4 Filipino       Women   2018
16 Hmong         10.2 Hmong          All     2018
17 Cambodian     13.8 Cambodian      All     2018
18 Asian          6.2 Asian          All     2018
19 Asian          6.4 Asian          Men     2018
20 Asian          6.1 Asian          Women   2018

You may notice that Gender is coded differently for the two years. Let’s make this consistent now:

We can combine these two tibbles using the bind_rows() function of dplyr.

Notice that there are some cases where we only have one value for a praticular group. For example, there are no male or female values for the Pakistani data.

We would like to have NA values for the comprable years/genders that are possible. We can fill out the rest of the table with NA values by performing the pivot_wider() and pivot_longer() functions sequentially like so:

Great, now we are ready to peform similar wrangling for the Latinx subgroups.

Latinx Subgroups 2018

Recall that this was the page with the table of interest for the Latinx subgroup 2018 data:

In this case only a single image was needed:

[1] "SOUTH :\n\nAMERICAN : 8.0\nMen 7.5\nMEXICAN 12.9\nMen 12.0\nWomen 13.8\nPR, DR, CUBAN 13.7\nMen 14.9\nWomen 12.4\nCENTRAL\n\nAMERICAN : 13.7\nMen 11.8\nWomen : 15.9\n"

Let’s first combine the South and Central American labels. Notice that there are multiple new line expressions in between and we dont see repeated \n characters elsewhere. We can replace the pattern of exactly two \n (using \n{2} to specify exactly 2) or two newline regex with a space and colon in front with a single space.

[1] "SOUTH AMERICAN : 8.0\nMen 7.5\nMEXICAN 12.9\nMen 12.0\nWomen 13.8\nPR, DR, CUBAN 13.7\nMen 14.9\nWomen 12.4\nCENTRAL AMERICAN : 13.7\nMen 11.8\nWomen : 15.9\n"
# A tibble: 12 x 1
   value                    
   <chr>                    
 1 "SOUTH AMERICAN : 8.0"   
 2 "Men 7.5"                
 3 "MEXICAN 12.9"           
 4 "Men 12.0"               
 5 "Women 13.8"             
 6 "PR, DR, CUBAN 13.7"     
 7 "Men 14.9"               
 8 "Women 12.4"             
 9 "CENTRAL AMERICAN : 13.7"
10 "Men 11.8"               
11 "Women : 15.9"           
12 ""                       
# A tibble: 11 x 4
   Group            Percent Race_Ethnicity   Gender
   <chr>              <dbl> <chr>            <chr> 
 1 South American       8   South American   All   
 2 Men                  7.5 South American   Men   
 3 Mexican             12.9 Mexican          All   
 4 Men                 12   Mexican          Men   
 5 Women               13.8 Mexican          Women 
 6 Pr, Dr, Cuban       13.7 Pr, Dr, Cuban    All   
 7 Men                 14.9 Pr, Dr, Cuban    Men   
 8 Women               12.4 Pr, Dr, Cuban    Women 
 9 Central American    13.7 Central American All   
10 Men                 11.8 Central American Men   
11 Women               15.9 Central American Women 

Again we will replace Pr, Dr, Cuban:

We also want to add the total Latinx values according to the text:

Question Opportunity

Can you recall how to add additional rows?

Click here to reveal the code.

# A tibble: 6 x 4
  Group            Percent Race_Ethnicity   Gender
  <chr>              <dbl> <chr>            <chr> 
1 Central American    13.7 Central American All   
2 Men                 11.8 Central American Men   
3 Women               15.9 Central American Women 
4 Latinx              12.8 Latinx           All   
5 Latinx              12.3 Latinx           Men   
6 Latinx              13.3 Latinx           Women 

And now we will recode gender like before to be consistent:

# A tibble: 6 x 4
  Group                          Percent Race_Ethnicity                 Gender
  <chr>                            <dbl> <chr>                          <chr> 
1 South American                     8   South American                 All   
2 Male                               7.5 South American                 Male  
3 Mexican                           12.9 Mexican                        All   
4 Male                              12   Mexican                        Male  
5 Female                            13.8 Mexican                        Female
6 Puerto Rican, Dominican, Cuban    13.7 Puerto Rican, Dominican, Cuban All   

Now we just need to combine all the data for the Latinx subgroups.

Again, first we will add a year variable to both the 2017 and 2018 data.

# A tibble: 32 x 5
   Group                   Percent Race_Ethnicity   Gender  Year
   <chr>                     <dbl> <chr>            <chr>  <dbl>
 1 Latinx                     13.2 Latinx           All     2017
 2 Latinx Male                12.4 Latinx           Male    2017
 3 Latinx Female              13.9 Latinx           Female  2017
 4 South American              8.4 South American   All     2017
 5 South American Male         9.1 South American   Male    2017
 6 South American Female       7.7 South American   Female  2017
 7 Central American           12   Central American All     2017
 8 Central American Male       9.3 Central American Male    2017
 9 Central American Female    15   Central American Female  2017
10 Mexican                    13.3 Mexican          All     2017
# … with 22 more rows

Again, we would like to have NA values for the comprable years/genders that are possible. We will fill out the rest of the table with NA values by performing the pivot_wider() and pivot_longer() functions sequentially like so:

Checking the data

OK, now let’s make sure that our notations match across our different tables. For example in the first report the terms male and female where used, but in the second report men and women were used. Let’s make sure everything is consistent now.

# A tibble: 108 x 5
   Group         Race_Ethnicity Gender  Year Percent
   <chr>         <chr>          <chr>  <dbl>   <dbl>
 1 United States All_races      All     2008    12.6
 2 United States All_races      All     2010    14.7
 3 United States All_races      All     2012    14.1
 4 United States All_races      All     2014    13.2
 5 United States All_races      All     2016    11.7
 6 United States All_races      All     2017    11.5
 7 Male          All_races      Male    2008    12.3
 8 Male          All_races      Male    2010    15.2
 9 Male          All_races      Male    2012    14.5
10 Male          All_races      Male    2014    13.3
# … with 98 more rows
# A tibble: 45 x 5
   Group          Percent Race_Ethnicity Gender  Year
   <chr>            <dbl> <chr>          <chr>  <dbl>
 1 United States     11.5 All_races      All     2017
 2 Male              11.8 All_races      Male    2017
 3 Female            11.1 All_races      Female  2017
 4 Asian              6.6 Asian          All     2017
 5 Asian Male         6.5 Asian          Male    2017
 6 Asian Female       6.7 Asian          Female  2017
 7 Chinese            4.3 Chinese        All     2017
 8 Chinese Male       4.7 Chinese        Male    2017
 9 Chinese Female     3.9 Chinese        Female  2017
10 Vietnamese         5.5 Vietnamese     All     2017
# … with 35 more rows
# A tibble: 32 x 5
   Group                   Percent Race_Ethnicity   Gender  Year
   <chr>                     <dbl> <chr>            <chr>  <dbl>
 1 Latinx                     13.2 Latinx           All     2017
 2 Latinx Male                12.4 Latinx           Male    2017
 3 Latinx Female              13.9 Latinx           Female  2017
 4 South American              8.4 South American   All     2017
 5 South American Male         9.1 South American   Male    2017
 6 South American Female       7.7 South American   Female  2017
 7 Central American           12   Central American All     2017
 8 Central American Male       9.3 Central American Male    2017
 9 Central American Female    15   Central American Female  2017
10 Mexican                    13.3 Mexican          All     2017
# … with 22 more rows

Looks good!

Data Visualization


Recall what our main questions were?

Our main questions:

  1. How have youth disconnection rates in American youth changed since 2008?
  2. In particular, how has this changed for different gender and ethnic groups? Are any groups particularly disconnected?

Now that we have wrangled our data and made it easy to work with, let’s create some visualizations to explore these questions.

Major Race and Ethnic Groups Plot

We are particularly interested in being able to reproduce the plot below, as we would like to make similar looking plots.

In general, it is very useful to learn how to reproduce the style of a plot.

There are color identifying websites such as this.

Using one of these websites, we identify the hex triplet code for the color used in the visualization included in the PDF : #008393. Thus we will use this color our plot.

We can create a version of the above plot using the ggplot2 package of the tidyverse to create our plots.


Click here for an introduction about this package if you are new to using ggplot2

The ggplot2 package is generally intuitive for beginners because it is based on a grammar of graphics or the gg in ggplot2. The idea is that you can construct many sentences by learning just a few nouns, adjectives, and verbs. There are specific “words” that we will need to learn and once we do, you will be able to create (or “write”) hundreds of different plots.

The critical part to making graphics using ggplot2 is the data needs to be in a tidy format. Given that we have just spent time putting our data in tidy format, we are primed to take advantage of all that ggplot2 has to offer!

We will show how it is easy to pipe tidy data (output) as input to other functions that create plots. This all works because we are working within the tidyverse.

What is the ggplot() function? As explained by Hadley Wickham:

The grammar tells us that a statistical graphic is a mapping from data to aesthetic attributes (colour, shape, size) of geometric objects (points, lines, bars). The plot may also contain statistical transformations of the data and is drawn on a specific coordinates system.

ggplot2 Terminology:

  • ggplot - the main function where you specify the dataset and variables to plot (this is where we define the x and y variable names)
  • geoms - geometric objects
    • e.g. geom_point(), geom_bar(), geom_line(), geom_histogram()
  • aes - aesthetics
    • shape, transparency, color, fill, line types
  • scales - define how your data will be plotted
    • continuous, discrete, log, etc

The function aes() is an aesthetic mapping function inside the ggplot() object. We use this function to specify plot attributes (e.g. x and y variable names) that will not change as we add more layers.

Anything that goes in the ggplot() object becomes a global setting. From there, we use the geom objects to add more layers to the base ggplot() object. These will define what we are interested in illustrating using the data.


So for this first plot we just want to recreate the plot in the PDF. Thus we will use the major_groups_long tibble and we will filter for the "All" values of the Gender package. We also want to exclude the data for the United states. We can exclude the data from the US using the not equals != opperator like so:

# A tibble: 30 x 5
   Group Race_Ethnicity Gender  Year Percent
   <chr> <chr>          <chr>  <dbl>   <dbl>
 1 Asian Asian          All     2008     7.1
 2 Asian Asian          All     2010     8.5
 3 Asian Asian          All     2012     7.8
 4 Asian Asian          All     2014     7.9
 5 Asian Asian          All     2016     6.6
 6 Asian Asian          All     2017     6.6
 7 White White          All     2008     9.7
 8 White White          All     2010    11.7
 9 White White          All     2012    11.2
10 White White          All     2014    10.8
# … with 20 more rows

The data from the tables only included up to 2017, but this will still allow us to create a similar plot.

Now we have the data ready to make the plot… but how do we actually start making the plot?

First, we start with the ggplot() function of the ggplot2 package.

This function requires that the aesthetics aes() be specified. This involves choosing what variable will be plotted on the x-axis and the y axis. It also involves choosing variables to color or group our plot by.

In our case, we want to plot the percent of disconnection on the y-axis (thus the Percent varaible of the major_groups_long data) and the Year on the x-axis. We would like to separate each racial or ethnic group to have their own points/lines. Thus we will use the color argument for this variable to do this, as we intend to color our plot something other than black.

If we run the following code, we get an empty plot.

The next thing we need to do is add ggplot2 layers using the + to specify how we want the data to be displayed on our plot.

We would like both points and lines. We will use the geom_point() and geom_line() functions of the ggplot2 package to do this. Which ever layer we add first will be plotted first and therefore below the next layer. We will also specify the size of these elements using the size argument.

OK, not bad, but we have quite a bit to work on to make the style match.

First, we will update the x-axis and y-axis, to look more similar to the plot from the report. We can specify where the tick marks should be for each using breaks argument of the scale_x_continuous() and scale_y_continuous() functions (also of the ggplot2 package). These functions also allow for specification of the range or limits of the axis using the limits argument. We can use the base seq() function to create a sequence of numbers for each tick mark. We will make the x-axis upper limit a bit larger to allow for the image of the figure and the label for each group.

Next, we will change the color to match the one that we identified, by using the scale_color_manual() function of the ggplot2 package. This requires color values for each group. In our case, we have 5 groups, so we repeate this value 5 times using the base rep() function.

We will also change the overall look of the plot using the theme_classic() function. See here for a list of options.

Now let’s add some labels. We can add a title using the title argument and a y-axis title using the y argument of the labs() function.

Getting close!

Now we need to add figurine icons to the plot.

To add the figurines we can use icons from free resources like font awesome. See here for a link to svg options. Or we could also take a screenshot of just the figurine from the original plot. However, it is useful to know how to create similar icons if we didn’t have the orginal plot to work with.

Using a screenshot:

Now to add the image of the figurine to the plot we can use the draw_image() function of the cowplot package. We simply need to specify the name of the image, and then where we would like it to go according to the x- and y-axis and finaly the scaled size of the image. This scale argument takes a bit of trial and error.

Here we will add both images of the figurines to a couple of groups:

Nice!

Now we just need to add this for all of the groups and we also will want to replace our Native American label with a two line version so that we look as similar to the report plot as possible.

Question Opportunity

How might we change the Native American label to have two lines? (hint: think about how we separated the rows of our tables)

Click here to reveal the code.

Nice! Our plot looks very similar stylistically to the plot in the report.

We can see from this plot that Native Americans have a very high rate of youth disconnection, with roughly still a quarter of the population experiencing youth disconnection in this survey. Altough some groups show a downward trend, like the Latinx group, the level has been fairly stable since 2008, as we see that the slope of each line is fairly flat. We will investigate this further in our analysis.

Major Race and Ethnic Groups and Gender Plot

Now let’s create a similar plot for females and males. To do this we can simply use the facet_wrap() function. We need to specify what variable we want to facet by, in this case the Gender variable, by using the ~ symbol. We also want to set the scales argument to "free", so that we have a y-axis for both the female and male plots. See this case study for more information about faceting plots.

We also dont want to plot the "All" values for the Gender variable as we have already shown that in the previous plot, so we again exclude it.

Question Opportunity

How do we modify the code to not include the "All" values for the Gender variable?

Click here to reveal the code.

It’s a bit difficult to tell the Black female and Latinx female lines apart.

Let’s try adding another color for every other line. Again we will use the scale_color_manual() function to specify the colors of the lines and points on the plot.

We will use black as the other color. We can use the hex triplet code or we can write out the name of the color, in this case we will write "black". To specifically color each group differently, we can write the colors in the alphabetically order of the distinct values of Race_Ethnicity. Thus the first color listed will be the color for the Asian values, while the last will be the color for the White values.

Question Opportunity

Can you explain why we didn’t use a pipe in the previous code chunk?

Very interesting! By parsing the groups further into intersections of racial and ethnic groups with gender, we see that there are some very dramatic differences for the Black and Latinx groups. One postive thing that we cans see, is that there has been a steep decline in youth disconnection for Latinx females. Unfortunately the level of disconnection for females in 2008 was quite high, so now Latinx females have similar rates to Latinx males. In contrast, we see that Black males have had and continue to have much higher rates of disconnection than Black females. Both Black females and males show an increased rate since 2016. Native American females also show an increased rate since 2016.

Subgroup plots

It is clear from the previous plot that observing more specific subgroups in our data can be very informative!

Thus, we also want to make plots of the Asain and Latinx subgroups, to see if there are particular ethnic groups that have higher levels of youth disconnection. If so, these groups may particuarly benefit for prevention and rengagement efforts.

We will also attempt to continue to plot the genders separately, as we have learned that there may be important gender group differences among the racial and ethnic groups. However, the data is incomplete for some of the ethnic groups. Recall that we also only have two years of data for both our Asian and Latinx subgroup data. First we will start by plotting just the subgroups over the two years.

We can continue to make our plots look like they match the report by using a color palette based off the color used in the report. We can use the colorRampPalette() function of the grDevices package, which is loaded automatically in an RStudio session. We can specify that we want the colors to range from gray to the color that we have been using.

Then we just need to specify how many colors we want in our gradient when we choose to use the color pallette. Say we wanted 3 colors, we just need to type custom_pal(3) to get a list of 3 colors within the palette. Thus we will have gray, the teal color we have been using, and a shade in between.

Here we can see the hex triplet codes for gray and the shade in between.

OK, now let’s start with the Asian subgroups. Since we only have two time points of data for each group, we will create a bar graph this time where the two years are displayed next to each other for each year. Thus, we want the Year variable to be a discrete variable. To ensure that it is interpreted as a discrete variable, we need to convert it to be a character type variable rather than numeric using the base as.character() function.

First, we want to filter for the rows where the Gender variable values are All, we also do not want to include the data for the average of all races. We also

# A tibble: 17 x 5
   Group       Percent Race_Ethnicity Gender Year 
   <chr>         <dbl> <chr>          <chr>  <chr>
 1 Asian           6.6 Asian          All    2017 
 2 Chinese         4.3 Chinese        All    2017 
 3 Vietnamese      5.5 Vietnamese     All    2017 
 4 Indian          5.9 Indian         All    2017 
 5 Pakistani       6.4 Pakistani      All    2017 
 6 Korean          6.5 Korean         All    2017 
 7 Two Or More     6.6 Two Or More    All    2017 
 8 Filipino        7.3 Filipino       All    2017 
 9 Hmong          14   Hmong          All    2017 
10 Chinese         4.1 Chinese        All    2018 
11 Indian          5.4 Indian         All    2018 
12 Korean          5.5 Korean         All    2018 
13 Vietnamese      6.3 Vietnamese     All    2018 
14 Filipino        6.8 Filipino       All    2018 
15 Hmong          10.2 Hmong          All    2018 
16 Cambodian      13.8 Cambodian      All    2018 
17 Asian           6.2 Asian          All    2018 

Now that we have wrangled the data we can make our plot. To make a bar plot there ae two many ggplot2 functions, geom_col() and geom_bar(). The geom_col() function plots the actual values of the data, while the geom_bar()function plots counts (however you can override this with the stat = identity argument). We are interested in plotting the actual values, so we will use the goem_col() function.

This time we will specify that the Year variable be used to specify the fill color of the bars of the bar plot by using aes(fill = Year).

We also need to indicate how the bars should be plotted based on the position argument.

The options for the position argument are: - stack - the years would be displayed on top of one another (this is default)
- dodge - the years would be displayed next to one another with no space in between
- dodge2 - the years would be displayed next to one another with a space in between
- fill - the years would be displayed on top of one other, where the heights of each color would show the relative proportions for each year adding up to 1, thus each bar would have the same height

We will use the dodge option.

For the colors, we can try out various numbers of shades for the palette till we get shades that we like. In this case, 2 shades out of a gradient of 4 shades from gray to teal looks nice,

OK, this looks pretty nice! However, we can improve this a bit.

Before we do so, let’s create a theme for our future similar ggplots like so:

Now we simply need to type bar_theme() instead to achieve the same style for our plot.

It would be nice if for subgroups that only have one year of data, if the column that was displayed was still the same width as the that of the other groups. To do this we need a row with an NA value for the year that is missing. One way to accomplish this is to use the pivot_wider() and pivot_longer() functions to widen the data based on the Year variable and the collapse the data based on the Year variable. By widening our data, we create the NA values we want; however we need to collapse our data back to the long format so that we can easily use ggplot2 to plot the year as the fill in our bar plot.

Note that we no longer need to change the type of the Year variable, as it is automatically converted to type character.

# A tibble: 10 x 4
   Race_Ethnicity Gender `2017` `2018`
   <chr>          <chr>   <dbl>  <dbl>
 1 Asian          All       6.6    6.2
 2 Chinese        All       4.3    4.1
 3 Vietnamese     All       5.5    6.3
 4 Indian         All       5.9    5.4
 5 Pakistani      All       6.4   NA  
 6 Korean         All       6.5    5.5
 7 Two Or More    All       6.6   NA  
 8 Filipino       All       7.3    6.8
 9 Hmong          All      14     10.2
10 Cambodian      All      NA     13.8

Great! Now we have NA values. Now we just to get the data back into long format:

# A tibble: 20 x 4
   Race_Ethnicity Gender Year  Percent
   <chr>          <chr>  <chr>   <dbl>
 1 Asian          All    2017      6.6
 2 Asian          All    2018      6.2
 3 Chinese        All    2017      4.3
 4 Chinese        All    2018      4.1
 5 Vietnamese     All    2017      5.5
 6 Vietnamese     All    2018      6.3
 7 Indian         All    2017      5.9
 8 Indian         All    2018      5.4
 9 Pakistani      All    2017      6.4
10 Pakistani      All    2018     NA  
11 Korean         All    2017      6.5
12 Korean         All    2018      5.5
13 Two Or More    All    2017      6.6
14 Two Or More    All    2018     NA  
15 Filipino       All    2017      7.3
16 Filipino       All    2018      6.8
17 Hmong          All    2017     14  
18 Hmong          All    2018     10.2
19 Cambodian      All    2017     NA  
20 Cambodian      All    2018     13.8

Great, now let’s see how this looks in the plot.

Great! that is looking better! However, currently the subgroups are plotted on the x-axis by alphabetically order and we want to instead order the subgroups based on the percentage of youth disconnection. We can use the forcats package to do this.

The fct_reorder() function can be used to order the Race_Ethnicity variable based on the average of the Percent variable for the two years, while the fct_relevel() function can be used to make the Asian level appear first for comparison sake. Imporantly, we need to do this before we reshape the data, because subgroups with NA values will be placed at the end.

This is looking very good! Now, let’s make a gap between the Asian average group and the subgroups to more easily differentiate between the two and let’s use that space to add the figure legend to the plot itself.

To first make a gap, we can use the scale_x_discrete() function. We need to write the name of the levels of the Race_Ethnicity variable and place a blank in between the Asian level and the subsequent levels. We can use the levels() function to make this more reproducible and to avoid mistakes instead of actually writing out each of the levels by hand.

Here you can see all the levels:

 [1] "Asian"       "Chinese"     "Indian"      "Vietnamese"  "Korean"     
 [6] "Pakistani"   "Two Or More" "Filipino"    "Hmong"       "Cambodian"  

To simplify our code we will save our wrangled data as a tibble called asain_for_plot.

So we would like our x-axis to be like this:

The levels(pull(asian_for_plot,Race_Ethnicity))[2:10]) code gets all 9 other levels but the Asian level of the Race_Ethnicity variable. The labels argument specifies what the x-axis should say for the spaces in between. We would like them to say nothing, so we use nothing within quotes "" as the label.

We can also use this as an opportunity to change the label on the plot for the Asian level of the Race_Ethnicity variable to be "Asian avg.". We dont wan’t to change the other subgroup level labels so we will not list anything.

We can make this more repreducible by using the length() function istead of the number 10 and replacing Asian with the first level:

Then we can use legend.justification and legend.position of the theme() function to move our legend to the plot area.

According to the documentaation for the theme() function of the ggplot2 package, the legend.justification argument specifies the:

anchor point for positioning legend inside plot (“center” or two-element numeric vector) or the justification according to the plot area when positioned outside the plot

By setting the mapping for the positioning and justifacation as c(0.12,0.1) we specify that we want the legend to be 12 percent of the plot area from the y -axis and 10 percent of the plot area from the x-axis.

Nice! But, this is still missing something. Perhaps if we add lines that show the average dissconection rate for the US and for Asians in general, then it will make it easier to see differences in our plot.

In the previous code we saved our plot to a onject called asian_subgroup_plot.

We can modify it by adding layers to add the lines that we want.

First we want to create objects for the US average and asian average disconnection rates.

First we want to create tibbles for the US Asian average disconnection rates. We want to add labels to each of these. We can use the parse = TRUE argument later with the geom_text() function of the ggplot2 package to make these labels appear as bold font as it will be evaluated as an expression istead of a simple character string.

# A tibble: 1 x 6
  Group Percent Race_Ethnicity Gender Year  label                          
  <chr>   <dbl> <chr>          <chr>  <chr> <chr>                          
1 Asian     6.6 Asian          All    2017  "bold(\"ASIAN 2017 AVG RATE\")"
# A tibble: 1 x 6
  Group         Percent Race_Ethnicity Gender Year  label                       
  <chr>           <dbl> <chr>          <chr>  <chr> <chr>                       
1 United States    11.5 All_races      All    2017  "bold(\"US 2017 AVG RATE\")"

Now we can use these to create labels again with the geom_text() function and lines with the geom_hline() function on our plot.

The geom_text() function requires that the x and y axis location for the text be specified, and we want this to be located near the actual percent dissoncation rate, thus we use the Percent +.5 to grab the Percent value from asian_total and add 0.5 to it to be slightly above where the line will be.

The geom_hline() function requires, just the yintercept as this function always creates a horizontal line. The linetype argument specifies what style of line we would like. See here for a list of options.

Awesome! Now it is much easier to tell how the disconnection rates for various subgroups compare to the national average and the Asian average. From our plot, we can see that the Hmong and Cambodian subgroup rates are very high. If we only had the plot of major racial and ethnic groups to rely on, we might not realize that these two groups have such high rates.

Nice! This shows the importance of adding small details such as the US and Asian rate lines. This helps provide a simple yet nuanced picture of what is going on.

From the above plot, it becomes readily apparent that the Hmong and Cambodian subgroups have much higher disconnection rates than the other Asian subgroups, as well as all races/ethnicities in the US combined.

We can confirm this by revisiting the tables.

From the 2018 table, we can caluculate that the Hmong group represented 5% and the Cambodian subgroup represented 4% respectively of all Asian disconnected youth in 2017.

If we wanted to make a similar plot but without the subgroups that are missing a year we could do it like so, by adding the drop_na() function of the tidyr package to remove rows with NA values when the data is in wide form and then using the fct_drop() function of the forcats package to remove the levels of the Race_Ethnicity variable that no longer have rows in the data.

asian_for_plot <-asian_subgroups %>%
  dplyr::select(-Group) %>%
  filter(Gender == "All") %>%
  filter(Race_Ethnicity != "All_races") %>%
  mutate(Race_Ethnicity =  fct_reorder(Race_Ethnicity, Percent)) %>% 
  mutate(Race_Ethnicity = fct_relevel(Race_Ethnicity, "Asian")) %>%
  pivot_wider(names_from = Year, values_from = Percent) %>%
  tidyr::drop_na() %>%
  pivot_longer(cols = -c(Race_Ethnicity, Gender), 
  names_to = "Year" , 
  values_to = "Percent")%>%
  mutate(Race_Ethnicity = fct_drop(Race_Ethnicity))

asian_subgroup_plot_simp <-asian_for_plot %>%
ggplot(aes(x = Race_Ethnicity, y = Percent, fill = Year)) +
 geom_col(aes(fill = Year), position = "dodge")+
  labs(title = "YOUTH DISCONNECTION BY ASIAN SUBGROUP AND YEAR",
       subtitle = "ORDERED BY AVERAGE DISCONNECTION LEVEL OF 2017 & 2018",
       y = "YOUTH DISCONNECTION (%)") +
  scale_fill_manual(values = custom_pal) +
  scale_x_discrete(
  limits = c(levels(pull(asian_for_plot,Race_Ethnicity))[1],
             "Blank",
             "NEXT_blank",
             levels(pull(asian_for_plot,Race_Ethnicity))[2:
             length(levels(pull(asian_for_plot,Race_Ethnicity)))]),
  labels = c("Asian" = "Asian Avg.",
             "Blank" = "",
             "NEXT_blank"= ""))+
  scale_y_continuous(limits = c(0,max(pull(asian_subgroups,Percent), 
                                       na.rm = TRUE)))+
  bar_theme()+
  #this add the legend to the plot area!:
  theme(legend.justification = c(0.16,0.01),legend.position = c(0.16,.01))+  geom_text(data = asian_total,
         mapping = aes(x = 2.5, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393", 
            size = 4) +
  geom_hline(aes(yintercept = pull(asian_total, Percent)), linetype = 2) +
  geom_text(data = US_total,
         mapping = aes(x = 2.5, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393", 
            size = 4) +
  geom_hline(aes(yintercept = pull(US_total, Percent)), linetype = 3)

Now let’s do the same for the Latinx subgroups.

Latinx Subgroups

First let’s make the small tibble of the 2017 Latinx average rate like we did for the US and for Asians to create the lines and text on our plot.

latinx_for_plot <-latinx_subgroups %>%
  dplyr::select(-Group) %>%
  filter(Gender == "All") %>%
  filter(Race_Ethnicity != "All_races") %>%
  mutate(Race_Ethnicity = str_replace(
                 string = Race_Ethnicity, 
                pattern = "Puerto Rican, Dominican, Cuban",
            replacement = "Puerto Rican,\nDominican,\nCuban")) %>%
  mutate(Race_Ethnicity =  fct_reorder(Race_Ethnicity, Percent)) %>% 
  mutate(Race_Ethnicity = fct_relevel(Race_Ethnicity, "Latinx")) %>%
  pivot_wider(names_from = Year, values_from = Percent) %>%
  pivot_longer(cols = -c(Race_Ethnicity, Gender), 
  names_to = "Year" , 
  values_to = "Percent")

latinx_subgroup_plot<-latinx_for_plot %>%
ggplot(aes(x = Race_Ethnicity, y = Percent, fill = Year)) +
 geom_col(aes(fill = Year), position = "dodge")+
  labs(title = "YOUTH DISCONNECTION BY LATINX SUBGROUP AND YEAR",
    subtitle = "ORDERED BY AVERAGE DISCONNECTION LEVEL OF 2017 & 2018",
           y = "YOUTH DISCONNECTION (%)") +
  scale_fill_manual(values = custom_pal) +
  scale_x_discrete(
  limits = c(levels(pull(latinx_for_plot,Race_Ethnicity))[1],
             "Blank",
             "NEXT_blank",
             levels(pull(latinx_for_plot,Race_Ethnicity))[2:
             length(levels(pull(latinx_for_plot,Race_Ethnicity)))]),
  labels = c("Latinx" = "Latinx Avg.",
             "Blank" = "",
             "NEXT_blank"= ""))+
  bar_theme()+
  #this add the legend to the plot area!:
  theme(legend.justification = c(0.23,0.1),legend.position = c(0.23,.1))+
  geom_text(data = latinx_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393", 
            size = 4) +
  geom_hline(aes(yintercept = pull(latinx_total, Percent)), linetype = 2) +
  geom_text(data = US_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393", 
            size = 4) +
  geom_hline(aes(yintercept = pull(US_total, Percent)), linetype = 3)

latinx_for_plot <-latinx_subgroups %>%
  dplyr::select(-Group) %>%
  filter(Gender == "All") %>%
  filter(Race_Ethnicity != "All_races") %>%
  mutate(Race_Ethnicity = str_replace(
                 string = Race_Ethnicity, 
                pattern = "Puerto Rican, Dominican, Cuban",
            replacement = "Puerto Rican,\nDominican,\nCuban")) %>%
  mutate(Race_Ethnicity =  fct_reorder(Race_Ethnicity, Percent)) %>% 
  mutate(Race_Ethnicity = fct_relevel(Race_Ethnicity, "Latinx")) %>%
  pivot_wider(names_from = Year, values_from = Percent) %>%
  tidyr::drop_na() %>%
  pivot_longer(cols = -c(Race_Ethnicity, Gender), 
  names_to = "Year" , 
  values_to = "Percent")%>%
  mutate(Race_Ethnicity = fct_drop(Race_Ethnicity))

latinx_subgroup_plot_simp <-latinx_for_plot %>%
ggplot(aes(x = Race_Ethnicity, y = Percent, fill = Year)) +
 geom_col(aes(fill = Year), position = "dodge")+
  labs(title = "YOUTH DISCONNECTION BY LATINX SUBGROUP AND YEAR",
    subtitle = "ORDERED BY AVERAGE DISCONNECTION LEVEL OF 2017 & 2018",
           y = "YOUTH DISCONNECTION (%)") +
  scale_fill_manual(values = custom_pal) +
  scale_x_discrete(
  limits = c(levels(pull(latinx_for_plot,Race_Ethnicity))[1],
             "Blank",
             "NEXT_blank",
             levels(pull(latinx_for_plot,Race_Ethnicity))[2:
             length(levels(pull(latinx_for_plot,Race_Ethnicity)))]),
  labels = c("Latinx" = "Latinx Avg.",
             "Blank" = "",
             "NEXT_blank"= ""))+
  scale_y_continuous(limits = c(0,max(pull(latinx_subgroups,Percent), 
                                       na.rm = TRUE)))+
  bar_theme()+
  #this add the legend to the plot area!:
  theme(legend.justification = c(0.23,0.01),legend.position = c(0.23,.01))+
  geom_text(data = latinx_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393", 
            size = 4) +
  geom_hline(aes(yintercept = pull(latinx_total, Percent)), linetype = 2) +
  geom_text(data = US_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393", 
            size = 4) +
  geom_hline(aes(yintercept = pull(US_total, Percent)), linetype = 3)

Subgroup by Gender Plots

Now that we have made plots for the ethnic subgroups, let’s take a look at gender differences among the subgroups.

# A tibble: 1 x 6
  Group Percent Race_Ethnicity Gender Year  label                          
  <chr>   <dbl> <chr>          <chr>  <chr> <chr>                          
1 Asian     6.6 Asian          All    2017  "bold(\"ASIAN 2017 AVG RATE\")"
# A tibble: 1 x 6
  Group         Percent Race_Ethnicity Gender Year  label                       
  <chr>           <dbl> <chr>          <chr>  <chr> <chr>                       
1 United States    11.5 All_races      All    2017  "bold(\"US 2017 AVG RATE\")"
asian_for_plot <-asian_subgroups %>%
  filter(Gender != "All") %>%
  filter(Race_Ethnicity != "All_races") %>%
    add_row(Race_Ethnicity = "Hmong",
          Gender = "Female",
          Year = 2017,
          Percent = NA) %>%
  mutate(Race_Ethnicity =  fct_reorder(Race_Ethnicity, Percent)) %>% 
  mutate(Race_Ethnicity = fct_relevel(Race_Ethnicity, "Asian")) %>%
  select(-Group) %>%
  pivot_wider(names_from = Year, values_from = Percent) %>%
  pivot_longer(cols = -c(Race_Ethnicity, Gender), 
  names_to = "Year" , 
  values_to = "Percent")


asian_gender_subgroup_plot<-asian_for_plot %>%
ggplot(aes(x = Race_Ethnicity, y = Percent)) +
geom_col(aes(fill = Gender), position = "dodge")+
  labs(title = "YOUTH DISCONNECTION BY ASIAN SUBGROUP AND GENDER",
    subtitle = "ORDERED BY AVERAGE DISCONNECTION LEVEL OF FEMALES & MALES (2017-2018)",
           y = "YOUTH DISCONNECTION (%)") +
  scale_fill_manual(values =(gender_pal)) +
  scale_x_discrete(
  limits = c(levels(pull(asian_for_plot,Race_Ethnicity))[1],
             "Blank",
             "Next_Blank",
             levels(pull(asian_for_plot,Race_Ethnicity))[2:
             length(levels(pull(asian_for_plot,Race_Ethnicity)))]),
  labels = c("Asian" = "Asian Avg.",
             "Blank" = "",
             "Next_Blank" = ""))+
   scale_y_continuous(limits = c(0,max(pull(asian_subgroups,Percent), 
                                       na.rm = TRUE)))+
  bar_theme()+
  theme(legend.justification = c(0.18,0.01), legend.position = c(0.18,.01))+
   geom_text(data = asian_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393",
            size = 4) +
  geom_hline(aes(yintercept = pull(asian_total, Percent)), linetype = 2) +
  geom_text(data = US_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393", 
            size = 4) +
  geom_hline(aes(yintercept = pull(US_total, Percent)), linetype = 3)

  asian_gender_subgroup_plot

latinx_for_plot <-latinx_subgroups %>%
  dplyr::select(-Group) %>%
  filter(Gender != "All") %>%
  filter(Race_Ethnicity != "All_races") %>%
  mutate(Race_Ethnicity = str_replace(
                 string = Race_Ethnicity, 
                pattern = "Puerto Rican, Dominican, Cuban",
            replacement = "Puerto Rican,\nDominican,\nCuban")) %>%
  mutate(Race_Ethnicity =  fct_reorder(Race_Ethnicity, Percent)) %>% 
  mutate(Race_Ethnicity = fct_relevel(Race_Ethnicity, "Latinx")) %>%
  pivot_wider(names_from = Year, values_from = Percent) %>%
  pivot_longer(cols = -c(Race_Ethnicity, Gender), 
  names_to = "Year" , 
  values_to = "Percent")

latinx_gender_subgroup_plot<-latinx_for_plot %>%
ggplot(aes(x = Race_Ethnicity, y = Percent)) +
geom_col(aes(fill = Gender), position = "dodge")+
  labs(title = "YOUTH DISCONNECTION BY LATINX SUBGROUP AND GENDER",
    subtitle = "ORDERED BY AVERAGE DISCONNECTION LEVEL OF FEMALES & MALES (2017-2018)",
           y = "YOUTH DISCONNECTION (%)") +
  scale_fill_manual(values = gender_pal) +
  scale_x_discrete(
  limits = c(levels(pull(latinx_for_plot,Race_Ethnicity))[1],
             "Blank",
             "Next_Blank",
             levels(pull(latinx_for_plot,Race_Ethnicity))[2:
             length(levels(pull(latinx_for_plot,Race_Ethnicity)))]),
  labels = c("Latinx" = "Latinx Avg.",
             "Blank" = "",
             "Next_Blank" = ""))+
   scale_y_continuous(limits = c(0,max(pull(latinx_subgroups,Percent), 
                                       na.rm = TRUE)))+
  
  bar_theme()+
    theme(legend.justification = c(0.18,0.01), legend.position = c(0.18,.01))+
   geom_text(data = latinx_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393",
            size = 4) +
  geom_hline(aes(yintercept = pull(latinx_total, Percent)), linetype = 2) +
  geom_text(data = US_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393", 
            size = 4) +
  geom_hline(aes(yintercept = pull(US_total, Percent)), linetype = 3)

  latinx_gender_subgroup_plot

Faceted Year and Gender Plots

asian_for_plot <-asian_subgroups %>%
  filter(Gender != "All") %>%
  filter(Race_Ethnicity != "All_races") %>%
    add_row(Race_Ethnicity = "Hmong",
          Gender = "Female",
          Year = 2017,
          Percent = NA) %>%
  mutate(Race_Ethnicity =  fct_reorder(Race_Ethnicity, Percent)) %>% 
  mutate(Race_Ethnicity = fct_relevel(Race_Ethnicity, "Asian")) %>%
  select(-Group) %>%
  pivot_wider(names_from = Year, values_from = Percent) %>%
  pivot_longer(cols = -c(Race_Ethnicity, Gender), 
  names_to = "Year" , 
  values_to = "Percent")


asian_gender_subgroup_plot_facet_year<-asian_for_plot %>%
ggplot(aes(x = Race_Ethnicity, y = Percent)) +
 geom_col(aes(fill = Gender), position = "dodge")+
  facet_wrap(~Year, scales = "free") +
  labs(title = "ASIAN SUBGROUP YOUTH DISCONNECTION BY GENDER",
    subtitle = "ORDERED BY AVERAGE DISCONNECTION LEVEL OF FEMALES & MALES (, 2017-2018)",
           y = "YOUTH DISCONNECTION (%)") +
  scale_fill_manual(values = gender_pal) +
  scale_x_discrete(
  limits = c(levels(pull(asian_for_plot,Race_Ethnicity))[1],
             "Blank",
             levels(pull(asian_for_plot,Race_Ethnicity))[2:
             length(levels(pull(asian_for_plot,Race_Ethnicity)))]),
  labels = c("Asian" = "Asian Avg.",
             "Blank" = ""))+
   scale_y_continuous(limits = c(0,max(pull(asian_subgroups,Percent), 
                                       na.rm = TRUE)))+
  bar_theme()+
   geom_text(data = asian_total,
         mapping = aes(x = 3.3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393",
            size = 3) +
  geom_hline(aes(yintercept = pull(asian_total, Percent)), linetype = 2) +
  geom_text(data = US_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393", 
            size = 3) +
  geom_hline(aes(yintercept = pull(US_total, Percent)), linetype = 3)

asian_for_plot <-asian_subgroups %>%
  filter(Gender != "All") %>%
  filter(Race_Ethnicity != "All_races") %>%
  mutate(Race_Ethnicity =  fct_reorder(Race_Ethnicity, Percent)) %>% 
  mutate(Race_Ethnicity = fct_relevel(Race_Ethnicity, "Asian")) %>%
  select(-Group) %>%
  pivot_wider(names_from = Year, values_from = Percent) %>%
  pivot_longer(cols = -c(Race_Ethnicity, Gender), 
  names_to = "Year" , 
  values_to = "Percent")

asian_gender_subgroup_plot_facet_sex<-asian_for_plot %>%
ggplot(aes(x = Race_Ethnicity, y = Percent, fill = Year)) +
 geom_col(aes(fill = Year), position = "dodge")+
  facet_wrap(~Gender, scales = "free") +
  labs(title = "ASIAN SUBGROUP YOUTH DISCONNECTION BY GENDER",
    subtitle = "ORDERED BY AVERAGE DISCONNECTION LEVEL OF 2017 & 2018",
           y = "YOUTH DISCONNECTION (%)") +
  scale_fill_manual(values = custom_pal) +
  scale_x_discrete(
  limits = c(levels(pull(asian_for_plot,Race_Ethnicity))[1],
             "Blank",
             levels(pull(asian_for_plot,Race_Ethnicity))[2:
             length(levels(pull(asian_for_plot,Race_Ethnicity)))]),
  labels = c("Asian" = "Asian Avg.",
             "Blank" = ""))+
   scale_y_continuous(limits = c(0,max(pull(asian_for_plot,Percent), 
                                       na.rm = TRUE)))+
  bar_theme()+
   geom_text(data = asian_total,
         mapping = aes(x = 3.3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "black", 
            size = 3) +
  geom_hline(aes(yintercept = pull(asian_total, Percent)), linetype = 2) +
  geom_text(data = US_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "black", 
            size = 3) +
  geom_hline(aes(yintercept = pull(US_total, Percent)), linetype = 3)

# A tibble: 1 x 6
  Group  Percent Race_Ethnicity Gender Year  label                           
  <chr>    <dbl> <chr>          <chr>  <chr> <chr>                           
1 Latinx    13.2 Latinx         All    2017  "bold(\"LATINX 2017 AVG RATE\")"
# A tibble: 1 x 6
  Group         Percent Race_Ethnicity Gender Year  label                       
  <chr>           <dbl> <chr>          <chr>  <chr> <chr>                       
1 United States    11.5 All_races      Male   2018  "bold(\"US 2017 AVG RATE\")"
latinx_for_plot <-latinx_subgroups %>%
  filter(Gender != "All") %>%
  filter(Race_Ethnicity != "All_races") %>%
  mutate(Race_Ethnicity = str_replace(
                 string = Race_Ethnicity, 
                pattern = "Puerto Rican, Dominican, Cuban",
            replacement = "Puerto Rican,\nDominican,\nCuban")) %>%
  mutate(Race_Ethnicity =  fct_reorder(Race_Ethnicity, Percent)) %>% 
  mutate(Race_Ethnicity = fct_relevel(Race_Ethnicity, "Latinx")) %>%
  select(-Group) %>%
  pivot_wider(names_from = Year, values_from = Percent) %>%
  pivot_longer(cols = -c(Race_Ethnicity, Gender), 
  names_to = "Year" , 
  values_to = "Percent")


latinx_gender_subgroup_plot_facet_year<-latinx_for_plot %>%
ggplot(aes(x = Race_Ethnicity, y = Percent)) +
 geom_col(aes(fill = Gender), position = "dodge")+
  facet_wrap(~Year, scales = "free") +
  labs(title = "LATINX SUBGROUP YOUTH DISCONNECTION BY GENDER",
    subtitle = "ORDERED BY AVERAGE DISCONNECTION LEVEL OF FEMALES & MALES (, 2017-2018)",
           y = "YOUTH DISCONNECTION (%)") +
  scale_fill_manual(values = gender_pal) +
  scale_x_discrete(
  limits = c(levels(pull(latinx_for_plot,Race_Ethnicity))[1],
             "Blank",
             levels(pull(latinx_for_plot,Race_Ethnicity))[2:
             length(levels(pull(latinx_for_plot,Race_Ethnicity)))]),
  labels = c("Latinx" = "Latinx Avg.",
             "Blank" = ""))+
   scale_y_continuous(limits = c(0,max(pull(latinx_subgroups,Percent), 
                                       na.rm = TRUE)))+
  bar_theme()+
   geom_text(data = latinx_total,
         mapping = aes(x = 3.3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393",
            size = 3) +
  geom_hline(aes(yintercept = pull(latinx_total, Percent)), linetype = 2) +
  geom_text(data = US_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "#008393", 
            size = 3) +
  geom_hline(aes(yintercept = pull(US_total, Percent)), linetype = 3)

latinx_for_plot <-latinx_subgroups %>%

  filter(Gender != "All") %>%
  filter(Race_Ethnicity != "All_races") %>%
  mutate(Race_Ethnicity = str_replace(
                 string = Race_Ethnicity, 
                pattern = "Puerto Rican, Dominican, Cuban",
            replacement = "Puerto Rican,\nDominican,\nCuban")) %>%
  mutate(Race_Ethnicity =  fct_reorder(Race_Ethnicity, Percent)) %>% 
  mutate(Race_Ethnicity = fct_relevel(Race_Ethnicity, "Latinx")) %>%
  select(-Group) %>%
  pivot_wider(names_from = Year, values_from = Percent) %>%
  pivot_longer(cols = -c(Race_Ethnicity, Gender), 
  names_to = "Year" , 
  values_to = "Percent")

latinx_gender_subgroup_plot_facet_sex<-latinx_for_plot %>%
ggplot(aes(x = Race_Ethnicity, y = Percent, fill = Year)) +
 geom_col(aes(fill = Year), position = "dodge")+
  facet_wrap(~Gender, scales = "free") +
  labs(title = " LATINX SUBGROUP YOUTH DISCONNECTION BY GENDER",
    subtitle = "ORDERED BY AVERAGE DISCONNECTION LEVEL OF 2017 & 2018",
           y = "YOUTH DISCONNECTION (%)") +
  scale_fill_manual(values = custom_pal) +
  scale_x_discrete(
  limits = c(levels(pull(latinx_for_plot,Race_Ethnicity))[1],
             "Blank",
             levels(pull(latinx_for_plot,Race_Ethnicity))[2:
             length(levels(pull(latinx_for_plot,Race_Ethnicity)))]),
  labels = c("Latinx" = "Latinx Avg.",
             "Blank" = ""))+
  bar_theme()+
  geom_text(data = latinx_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "black", 
            size = 3) +
  geom_hline(aes(yintercept = pull(latinx_total, Percent)), linetype = 2) +
  geom_text(data = US_total,
         mapping = aes(x = 3, y = Percent +.7, label = label),
           parse = TRUE,
           color = "black", 
            size = 3) +
  geom_hline(aes(yintercept = pull(US_total, Percent)), linetype = 3)

Data Analysis


Repeated Cross-sectional Data

We have pooled (repeated) cross-sectional data.

This is data produced from repeated measurement of a population over time.

It is often infeasible to collect data for an entire population at once. However, we can still obtain meaningful measures using a random sample of the population.

At specific time-points, data is collected from a sample of the population. The individuals in each sample are not necessarily the same individuals. This separates pooled cross-sectional data from panel data, which is longitudinal data from repeated measurement of the same people.

By sampling from a population at multiple time points, we can generate population level statistics. Although these statistics have some random error, they can provide insight into how the measure variable is changing in a population over time.

We can accomplish this by plotting the measured values over time. Sometimes, however, the trend isn’t exactly clear. Fortunately, there are statistical methods to resolve this issue.

The Mann-Kendall trend test—a variation of the Kendall rank correlation coefficient—tests whether there is a monotonic association, an association that does not increase or decrease but remains static across a dimension.

Recall the youth disconnection rates for Native Americans, some of the highest in the first table we examined.

Let’s conduct a Mann-Kendall test for trend.

We can accomplish this with the Kendall::MannKendall() function. The Kendall::MannKendall() accepts a vector of data for which a trend may be observed. Consulting the documentation for the Kendall::MannKendall() function available on CRAN, we can “test for a a monotonic trend in a time series”.

Score =  -7 , Var(Score) = 28.33333
denominator =  15
tau = -0.467, 2-sided pvalue =0.25966

There does not appear to be a change in the trend. However, it’s important to note that we only have 6 observations.

We can also explore the trend using simple linear regression.


Call:
lm(formula = Percent ~ Year, data = .)

Residuals:
      1       2       3       4       5       6 
-2.4332  2.2978  0.8288  0.4597  0.2907 -1.4438 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept) 359.1159   487.3956   0.737    0.502
Year         -0.1655     0.2421  -0.683    0.532

Residual standard error: 1.889 on 4 degrees of freedom
Multiple R-squared:  0.1045,    Adjusted R-squared:  -0.1193 
F-statistic: 0.467 on 1 and 4 DF,  p-value: 0.5319

For each one year change, the mean increase in disconnection rates is -0.1654795

This relationship is not statistically significant. Again, we are largely limited by the number of observations in this dataset.

We can visualize the relationship above.

As we can see, there is a large amount of uncertainty around the fitted line.

Suggested Homework


  1. Find another table in the document. Find differences between groups with the process described above.

Acknowledgements

We would like to acknowledge Tamar Mendelson for assisting in framing the major direction of the case study.

We would also like to acknowledge the Bloomberg American Health Initiative for funding this work.

LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXMgOiBEaXNwYXJpdGllcyBpbiBZb3V0aCBEaXNjb25uZWN0aW9uIgpjc3M6IHN0eWxlLmNzcwpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHNlbGZfY29udGFpbmVkOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgbnVtYmVyX3NlY3Rpb25zOiBubwogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwoKLS0tCgo8c3R5bGU+CiNUT0MgewogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL2ltZy9sb2dvLmpwZyIpOwogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsKICBwYWRkaW5nLXRvcDogMjQwcHggIWltcG9ydGFudDsKICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Owp9Cjwvc3R5bGU+CgoKPCEtLSBPcGVuIGFsbCBsaW5rcyBpbiBuZXcgdGFiLS0+ICAKPGJhc2UgdGFyZ2V0PSJfYmxhbmsiLz4gIAoKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgb3V0LndpZHRoID0gJzkwJScpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShrbml0cikKYGBgCgoKIyMjIyB7Lm91dGxpbmUgfQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIm1haW5wbG90LnBuZyIpKQpgYGAKCiMjIyMKCiMjIHsuZGlzY2xhaW1lcl9ibG9ja30KCioqRGlzY2xhaW1lcioqOiBUaGUgcHVycG9zZSBvZiB0aGUgW09wZW4gQ2FzZSBTdHVkaWVzXShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8pIHByb2plY3QgaXMgKip0byBkZW1vbnN0cmF0ZSB0aGUgdXNlIG9mIHZhcmlvdXMgZGF0YSBzY2llbmNlIG1ldGhvZHMsIHRvb2xzLCBhbmQgc29mdHdhcmUgaW4gdGhlIGNvbnRleHQgb2YgbWVzc3ksIHJlYWwtd29ybGQgZGF0YSoqLiBBIGdpdmVuIGNhc2Ugc3R1ZHkgZG9lcyBub3QgY292ZXIgYWxsIGFzcGVjdHMgb2YgdGhlIHJlc2VhcmNoIHByb2Nlc3MsIGlzIG5vdCBjbGFpbWluZyB0byBiZSB0aGUgbW9zdCBhcHByb3ByaWF0ZSB3YXkgdG8gYW5hbHl6ZSBhIGdpdmVuIGRhdGEgc2V0LCBhbmQgc2hvdWxkIG5vdCBiZSB1c2VkIGluIHRoZSBjb250ZXh0IG9mIG1ha2luZyBwb2xpY3kgZGVjaXNpb25zIHdpdGhvdXQgZXh0ZXJuYWwgY29uc3VsdGF0aW9uIGZyb20gc2NpZW50aWZpYyBleHBlcnRzLiAKCgojIyB7LmxpY2Vuc2VfYmxvY2t9CgpUaGlzIHdvcmsgaXMgbGljZW5zZWQgdW5kZXIgdGhlIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tTm9uQ29tbWVyY2lhbCAzLjAgWyhDQyBCWS1OQyAzLjApXShodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktbmMvMy4wL3VzLykgIFVuaXRlZCBTdGF0ZXMgTGljZW5zZS4KCgojIyB7LnJlZmVyZW5jZV9ibG9ja30KClRvIGNpdGUgdGhpcyBjYXNlIHN0dWR5IHBsZWFzZSB1c2U6CgpXcmlnaHQsIENhcnJpZSwgYW5kIE9udGl2ZXJvcywgTWljaGFlbCBhbmQgSmFnZXIsIExlYWggYW5kIFRhdWIsIE1hcmdhcmV0IGFuZCBIaWNrcywgU3RlcGhhbmllLiAoMjAyMCkuIGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLXlvdXRoLWRpc2Nvbm5lY3Rpb24tY2FzZS1zdHVkeS4gRGlzcGFyaXRpZXMgaW4gWW91dGggRGlzY29ubmVjdGlvbiAoVmVyc2lvbiB2MS4wLjApLgoKIyMgKipNb3RpdmF0aW9uKioKKioqIAoKQWNjb3JkaW5nIHRvIHRoaXMgW3JlcG9ydF0oaHR0cHM6Ly9zc3JjLXN0YXRpYy5zMy5hbWF6b25hd3MuY29tL21vYS9NYWtpbmclMjB0aGUlMjBDb25uZWN0aW9uLnBkZikgeW91dGggZGlzY29ubmVjdGlvbiBhbHRob3VnaCBnZW5lcmFsbHkgc2hvd2luZyBkZWNyZWFzaW5nIHRyZW5kcyBmb3IgdGhlIHBhc3QgNyB5ZWFycywgc2hvd3MgKipyYWNpYWwgYW5kIGV0aG5pYyBkaXNwYXJpdGllcyoqLCB3aGVyZSBzb21lIGdyb3VwcyBhcmUgc2hvd2luZyBpbmNyZWFzZWQgcmF0ZXMgb2YgZGlzY29ubmVjdGlvbi4KClNvIHdoYXQgZG9lcyB0aGUgdGVybSAqKiJ5b3V0aCBkaXNjb25uZWN0aW9uIioqIG1lYW4/CgpBY2NvcmRpbmcgdG8gW01lYXN1cmUgb2YgQW1lcmljYV0oaHR0cHM6Ly93d3cuc3NyYy5vcmcvcHJvZ3JhbXMvdmlldy9tb2EvKSAoYSBub25wYXJ0aXNhbiBwcm9qZWN0IG9mIHRoZSBub25wcm9maXQgW1NvY2lhbCBTY2llbmNlIFJlc2VhcmNoIENvdW5jaWxdKGh0dHBzOi8vd3d3LnNzcmMub3JnLykgdGhhdCBpcyBmb2N1c2VkIG9uIG9wcG9ydHVuaXR5IGluIHRoZSBVbml0ZWQgU3RhdGVzKSBkaXNjb25uZWN0ZWQgeW91dGggYXJlOgoKPiAieW91bmcgcGVvcGxlIGJldHdlZW4gdGhlIGFnZXMgb2YgKioxNiBhbmQgMjQqKiB3aG8gYXJlICoqbmVpdGhlciB3b3JraW5nIG5vciBpbiBzY2hvb2wqKiIKClRoZXkgc3RhdGUgdGhhdCBzdWNoIGRpc2Nvbm5lY3Rpb24gaGluZGVycyB0aGVzZSBpbmRpdmlkdWFscyB0byBhcXVpcmUgc2tpbGxzIGFuZCBjcmVhdGUgcmVsYXRpb25zaGlwcyBuZWNlc3NhcnkgdG8gaGF2ZSBhIHN1Y2Vzc2Z1bCBhZHVsdGhvb2QuIAoKVGhleSBzdGF0ZSB0aGF0OgoKPiAicGVvcGxlIHdobyBleHBlcmllbmNlIGEgcGVyaW9kIG9mIGRpc2Nvbm5lY3Rpb24gYXMgeW91bmcgYWR1bHRzIGdvIG9uIHRvICoqZWFybiBsZXNzKiogYW5kIGFyZSAqKmxlc3MgbGlrZWx5KiogdG8gYmUgKiplbXBsb3llZCwgb3duIGEgaG9tZSwgb3IgcmVwb3J0IGdvb2QgaGVhbHRoKiogYnkgdGhlIHRpbWUgdGhleSByZWFjaCB0aGVpciB0aGlydGllcyIKCkRpc2Nvbm5lY3RlZCB5b3V0aCBhcmUgYWxzbyByZWZlcnJlZCB0byBhcyAqKm9wcG9ydHVuaXR5IHlvdXRoKiosIHdoaWNoIGhhcyB0aGUgYWRkZWQgcG9zaXRpdmUgY29ubm90YXRpb24gdGhhdCBwcm9tb3Rpbmcgc3VjaCBpbmRpdmlkdWFscyBjYW4gYmUgYmVuZWZpY2lhbCBub3Qgb25seSBmb3IgdGhlc2UgaW5kaXZpZHVhbHMgYnV0IGFsc28gZm9yIHRoZWlyIGNvbW11bnRpZXMgYW5kIGZvciBzb2NpZXR5LiAKCldlIHdpbGwgZXhwYW5kIGJleW9uZCB0aGUgW01lYXN1cmUgb2YgQW1lcmljYSBhbm51YWwgcmVwb3J0XShodHRwczovL3NzcmMtc3RhdGljLnMzLmFtYXpvbmF3cy5jb20vbW9hL01ha2luZyUyMHRoZSUyMENvbm5lY3Rpb24ucGRmKSB0byB0YWtlIGEgZGVlcGVyIGxvb2sgYXQgZGlmZmVyZW5jZXMgb2Ygc3BlY2lmaWMgZ3JvdXBzIG9mIHlvdXRocy4gSWRlbnRpZnlpbmcgeW91dGhzIHBhcnRpY3VsYXJseSBhdCByaXNrIG9yIGRpc2Nvbm5lY3RlZCwgY2FuIGhlbHAgaW5mb3JtIHRoZSBkZXNpZ24gb2YgdGFyZ2V0ZWQgcHJldmVudGlvbiBhbmQgcmVuZ2FnZW1lbnQgc3RyYXRlZ2llcy4KClRoaXMgY2FzZSBzdHVkeSBpcyBtb3RpdmF0ZWQgYnkgdGhpcyBbYXJ0aWNsZV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNjI0MzQ0Ni8pOiAKCiMjIyMgey5yZWZlcmVuY2VfYmxvY2t9CgpNZW5kZWxzb24sIFQuLCBNbWFyaSwgSy4sIEJsdW0sIFIuIFcuLCBDYXRhbGFubywgUi4gRi4gJiBCcmluZGlzLCBDLiBELiBPcHBvcnR1bml0eSBZb3V0aDogSW5zaWdodHMgYW5kIE9wcG9ydHVuaXRpZXMgZm9yIGEgUHVibGljIEhlYWx0aCBBcHByb2FjaCB0byBSZWVuZ2FnZSBEaXNjb25uZWN0ZWQgVGVlbmFnZXJzIGFuZCBZb3VuZyBBZHVsdHMuICpQdWJsaWMgSGVhbHRoIFJlcCogMTMzLCA1NFMtNjRTICgyMDE4KS4KCiMjIyMKIApUaGlzIFthcnRpY2xlXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM2MjQzNDQ2LykgZGVzY3JpYmVzIHN0cmF0ZWdpZXMgZm9yIHByZXZlbnRpb24gb2YgZGlzY29ubmVjdGlvbiBhbmQgcmVlbmdhZ2VtZW50IG9mIGRpc2Njb25uZWN0ZWQgeW91dGggYW5kIGhvdyBzdWNoIGludGVydmVudGlvbnMgY291bGQgZ3JlYXRseSBwb3NpdGl2ZWx5IGltcGFjdCBvcHBvcnR1bml0eSB5b3V0aCBmb3IgdGhlIGVudGlyZSB0cmFqZWN0b3J5IG9mIHRoZWlyIGxpdmVzIGFuZCBmb3IgZnV0dXJlIGdlbmVyYXRpb25zLiBJdCBhbHNvIHBvaW50cyBvdXQgdGhhdCBpbmRlZWQgdGhlaXIgYXJlIGRpc3Bhcml0aWVzIGFtb25nIGRpZmZlcmVudCByYWNpYWwvZXRobmljIGdyb3Vwcy4KCgojIyAqKk1haW4gUXVlc3Rpb25zKioKKioqIAoKIyMjIyB7Lm1haW5fcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBPdXIgbWFpbiBxdWVzdGlvbnM6IDwvdT48L2I+CgoxKSBIb3cgaGF2ZSB5b3V0aCBkaXNjb25uZWN0aW9uIHJhdGVzIGluIEFtZXJpY2FuIHlvdXRoIGNoYW5nZWQgc2luY2UgMjAwOD8gICAKMikgSW4gcGFydGljdWxhciwgaG93IGhhcyB0aGlzIGNoYW5nZWQgZm9yIGRpZmZlcmVudCBnZW5kZXIgYW5kIGV0aG5pYyBncm91cHM/IEFyZSBhbnkgZ3JvdXBzIHBhcnRpY3VsYXJseSBkaXNjb25uZWN0ZWQ/IAoKIyMjIwoKIyMgKipMZWFybmluZyBPYmplY3RpdmVzKiogCioqKiAKCkluIHRoaXMgY2FzZSBzdHVkeSwgd2Ugd2lsbCBkZW1vbnN0cmF0ZSBob3cgdG8gaW1wb3J0IGFuZCB3cmFuZ2xlIGRhdGEgYXZhaWxhYmxlIGluIHRoZSA8dT4qKlAqKjwvdT5vcnRhYmxlIDx1PioqRCoqPC91Pm9jdW1lbnQgPHU+KipGKio8L3U+b3JtYXQgKCoqUERGKiopLiBXZSB3aWxsIGVzcGVjaWFsbHkgZm9jdXMgb24gdXNpbmcgcGFja2FnZXMgYW5kIGZ1bmN0aW9ucyBmcm9tIHRoZSBbYFRpZHl2ZXJzZWBdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKSwgc3VjaCBhcyBgZHBseXJgLCBgZ2dwbG90MmAuIFRoZSB0aWR5dmVyc2UgaXMgYSBsaWJyYXJ5IG9mIHBhY2thZ2VzIGNyZWF0ZWQgYnkgUlN0dWRpby4gV2hpbGUgc29tZSBzdHVkZW50cyBtYXkgYmUgZmFtaWxpYXIgd2l0aCBwcmV2aW91cyBSIHByb2dyYW1taW5nIHBhY2thZ2VzLCB0aGVzZSBwYWNrYWdlcyBtYWtlIGRhdGEgc2NpZW5jZSBpbiBSIG1vcmUgbGVnaWJsZSBhbmQgaW50dWl0aXZlLgoKVGhlIHNraWxscywgbWV0aG9kcywgYW5kIGNvbmNlcHRzIHRoYXQgc3R1ZGVudHMgd2lsbCBiZSBmYW1pbGlhciB3aXRoIGJ5IHRoZSBlbmQgb2YgdGhpcyBjYXNlIHN0dWR5IGFyZToKCkRhdGEgc2NpZW5jZSBza2lsbHM6ICAKCjEuIEltcG9ydGluZyBkYXRhIGZyb20gUERGIGZpbGVzIHVzaW5nIHRoZSBgbWFnaWNrYCBwYWNrYWdlICAKMi4gQXBwbHkgYWN0aW9uIHZlcmJzIGluIGBkcGx5cmAgZm9yIGRhdGEgd3JhbmdsaW5nICAKMy4gSG93IHRvIHBpdm90IGJldHdlZW4gImxvbmciIGFuZCAid2lkZSIgZGF0YXNldHMgKGB0aWR5cmApICAKNC4gSm9pbmluZyB0b2dldGhlciBtdWx0aXBsZSBkYXRhc2V0cyB1c2luZyBgZHBseXJgICAKNS4gSG93IHRvIGNyZWF0ZSBkYXRhIHZpc3VhbGl6YXRpb25zIHdpdGggYGdncGxvdDJgIHRoYXQgYXJlIGluIGEgc2ltaWxhciBzdHlsZSB0byBhbiBleGlzdGluZyBpbWFnZSAgCgpTdGF0aXN0aWNhbCBjb25jZXB0cyBhbmQgbWV0aG9kczogIAoKMS4gSW1wbGVtZW50YXRpb24gb2YgdGhlIE1hbm4tS2VuZGFsbCB0cmVuZCB0ZXN0ICAKMi4gSW50ZXJwcmV0YXRpb24gb2YgdGhlIE1hbm4tS2VuZGFsbCB0cmVuZCB0ZXN0ICAKCgpgYGB7ciwgb3V0LndpZHRoID0gIjIwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly90aWR5dmVyc2UudGlkeXZlcnNlLm9yZy9sb2dvLnBuZyIpCmBgYAoKKioqIAoKV2Ugd2lsbCBiZWdpbiBieSBsb2FkaW5nIHRoZSBwYWNrYWdlcyB0aGF0IHdlIHdpbGwgbmVlZDoKCmBgYHtyfQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KHBkZnRvb2xzKQpsaWJyYXJ5KG1hZ2ljaykKbGlicmFyeShkaXJlY3RsYWJlbHMpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShmb3JjYXRzKQpsaWJyYXJ5KEtlbmRhbGwpCmBgYAoKCgogUGFja2FnZSAgIHwgVXNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tCltoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YQpbdGlkeXZlcnNlXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKSAgICAgIHwgZm9yIGRhdGEgc2NpZW5jZSBvcGVyYXRpb25zCltwZGZ0b29sc10oaHR0cHM6Ly9yZWFkci50aWR5dmVyc2Uub3JnLykgICAgICB8IHRvIG1hbmFnZSBQREYgZG9jdW1lbnRzClttYWdpY2tdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdpY2svdmlnbmV0dGVzL2ludHJvLmh0bWwjS2VybmVsX2NvbnZvbHV0aW9uKSAgICAgIHwgZm9yIGltYWdlIHByb2Nlc3NpbmcgCltoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YQpbdGlkeXZlcnNlXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKSAgICAgIHwgZm9yIGRhdGEgc2NpZW5jZSBvcGVyYXRpb25zCltwZGZ0b29sc10oaHR0cHM6Ly9yZWFkci50aWR5dmVyc2Uub3JnLykgICAgICB8IHRvIG1hbmFnZSBQREYgZG9jdW1lbnRzClttYWdpY2tdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdpY2svdmlnbmV0dGVzL2ludHJvLmh0bWwjS2VybmVsX2NvbnZvbHV0aW9uKSAgICAgIHwgZm9yIGltYWdlIHByb2Nlc3NpbmcgCgoKVGhlIGZpcnN0IHRpbWUgd2UgdXNlIGEgZnVuY3Rpb24sIHdlIHdpbGwgdXNlIHRoZSBgOjpgIHRvIGluZGljYXRlIHdoaWNoIHBhY2thZ2Ugd2UgYXJlIHVzaW5nLiBVbmxlc3Mgd2UgaGF2ZSBvdmVybGFwcGluZyBmdW5jdGlvbiBuYW1lcywgdGhpcyBpcyBub3QgbmVjZXNzYXJ5LCBidXQgd2Ugd2lsbCBpbmNsdWRlIGl0IGhlcmUgdG8gYmUgaW5mb3JtYXRpdmUgYWJvdXQgd2hlcmUgdGhlIGZ1bmN0aW9ucyB3ZSB3aWxsIHVzZSBjb21lIGZyb20uCgojIyAqKkNvbnRleHQqKgoqKiogCgpTbyBob3cgZG9lcyB5b3V0aCBkaXNjb25uZWN0aW9uIGhhcHBlbiBhbmQgd2hhdCBpbXBhY3QgZG9lcyBpdCBoYXZlPwoKClRoZXJlIGFyZSBtYW55IGtub3duICoqcmlzayBmYWN0b3JzKiosIHdoaWNoIGhhdmUgYmVlbiBpZGVudGlmaWVkIGluIGEgdmFyaWV0eSBvZiBjb250ZXh0cyAoZnJvbSBmYW1pbHksIGZyaWVuZHMsIHNjaG9vbCwgY29tbXVuaXR5LCBzb2NpZXR5KSBpbmNsdWRpbmc6ICAKCiAtIHBvdmVydHkgKGRpc2Nvbm5lY3RlZCB5b3V0aCBhcmUgbmVhcmx5IHR3aWNlIGFzIGxpa2VseSB0byBsaXZlIGluIHBvdmVydHkgYW5kIHJlY2VpdmUgTWVkaWNhaWQpICAKIC0gcmFjaWFsL2V0aG5pYyBkaXNwYXJpdGllcyAoZmluZGluZ3Mgc3VnZ2VzdCB0aGF0IHRoZXNlIHBlcnNpc3QgZXZlbiB3aGVuIGNvbnRyb2xsaW5nIGZvciBpbmNvbWUpICAKIC0gcmVzaWRlbnRpYWwgZW52aXJvbm1lbnQgKGluIDIwMTYgd2hpbGUgMTEuNyUgd2FzIHRoZSBuYXRpb25hbCBhdmVyYWdlLCAyNCUgb2YgcGVvcGxlIGFnZSAxNi0yNCBpbiB0aGUgcnVyYWwgU291dGggd2VyZSBkaXNjb25uZWN0ZWQpICAKIC0gcG9vciBhY2FkZW1pYyBwZXJmb3JtYW5jZSAgCiAtIHBvb3IgbWVudGFsIGhlYWx0aCAgCiAtIHN1YnN0YW5jZSB1c2UgZGlzb3JkZXJzICAKIC0gcGFyZW50YWwgdW5lbXBsb3ltZW50ICAKIC0gdHJhdW1hIGV4cG9zdXJlICAKIC0gYXNzb2NpYXRpb24gd2l0aCBzb2NpYWxseSBkZXZpYW50IHBlZXJzIAogLSBzY2hvb2wgcG9saWNpZXMgc3VjaCBhcyAib25lIHN0cmlrZSBhbmQgeW91J3JlIG91dCIgLSB3aGljaCBpcyBhIHplcm8gdG9sZXJhbmNlIHNjaG9vbCBleHB1bHNpb24gcG9saWN5IGFuZCBzaG93biB0byBpbmNyZWFzZSBkcm9wb3V0cyBhbmQgaW5jYXJjZXJhdGlvbiByYXRlcwogCiBUaGVzZSByaXNrIGZhY3RvcnMgbWFrZSBpdCBtb3JlIGxpa2VseSBmb3IgeW91bmcgcGVvcGxlIHRvIG1pc3Mgb3V0IG9uIGVkdWNhdGlvbiwgdHJhaW5pbmcsIGFuZCBuZXR3b3JraW5nIHRoYXQgY2FuIGFjdCBhcyBhIGZvdW5kYXRpb24gZm9yIGEgc3VjZXNzZnVsIGNhcmVlci4KIApUaGVyZSBhcmUgYWxzbyBtYW55IGtub3duICoqbmVnYXRpdmUgY29uc2VxdWVuY2VzKiogYXNzb2NpYXRlZCB3aXRoIHlvdXRoIGRpc2Nvbm5lY3Rpb24gaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bzoKCi0gY2hyb25pYyB1bmVtcGxveW1lbnQKLSBwb3ZlcnR5Ci0gcG9vciBtZW50aGFsIGhlYWx0aCBhbmQgcG9vciBnZW5lcmFsIGhlYWx0aCAoaW4gYSAyMDAyIHN0dWR5IC0geW91dGhzIGRpc2Nvb25lY3RlZCBmb3IgNiBvciBtb3JlIG1vbnRocyB3ZXJlIDMgdGltZXMgbW9yZSBsaWtlbHkgdG8gZGV2ZWxvcCBkZXByZXNzaW9uIG9yIG90aGVyIG1lbnRhbCBoZWFsdGggZGlzb3JkZXIpCi0gY3JpbWlhbCBiZWhhdmlvciAoaW4gYSAyMDAyIHN0dWR5IC0geW91dGhzIGRpc2Nvb25lY3RlZCBmb3IgNiBvciBtb3JlIG1vbnRocyB3ZXJlIDUgdGltZXMgbW9yZSBsaWtlbHkgdG8gaGF2ZSBhIGNyaW1pbmFsIHJlY29yZCkKLSBpbmNhcmNlcmF0aW9uCi0gZWFybHkgbW9ydGFsaXR5IAoKCmBgYHtyLCBvdXQud2lkdGg9ICI0MDBweCIsZWNobz1GQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImpvbi10eXNvbi1hanpOMkFZTmkxVS11bnNwbGFzaC5qcGciKSkKYGBgCjxzcGFuPlBob3RvIGJ5IDxhIGhyZWY9Imh0dHBzOi8vdW5zcGxhc2guY29tL0Bqb250eXNvbj91dG1fc291cmNlPXVuc3BsYXNoJmFtcDt1dG1fbWVkaXVtPXJlZmVycmFsJmFtcDt1dG1fY29udGVudD1jcmVkaXRDb3B5VGV4dCI+Sm9uIFR5c29uPC9hPiBvbiA8YSBocmVmPSJodHRwczovL3Vuc3BsYXNoLmNvbS9zL3Bob3Rvcy91bmVtcGxveW1lbnQ/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPlVuc3BsYXNoPC9hPjwvc3Bhbj4KCkZ1cnRoZXJtb3JlLCBpbiAyMDEyIGl0IHdhcyBlc3RpbWF0ZWQgdGhhdCBlYWNoIGRpc2Nvbm5lY3RlZCB5b3V0aCBjb3N0cyB0YXhwYXllcnMgJDI1MDAwMCBkdXJpbmcgYSBsaWZlIHRpbWUgZHVlIHRvIGxvc3QgdGF4IHJldmVudWUgYW5kIGNvc3RzIGZvciBzb2NpYWwgc2VyY2ljZXMsIGhlYXRoIGNhcmUgYW5kIGNyaW1pbmFsIGp1c3RpY2UuCgpZb3V0aCBkaXNjb25uZWN0aW9uIGNhbiBiZSBkZXNjcmliZWQgYXMgYSBjb250aW51dW0sIGFzIHNvbWUgeW91dGhzIHdpbGwgYmUgZGlzY29ubmVjdGVkIGZvciBhIGJyaWVmIHRpbWUsIHdoaWxlIG90aGVycyBhcmUgY2hyb25pY2FsbHkgZGlzY29ubmVjdGVkLiBBZGRpdGlvbmFsbHksIHdoaWxlIGFuIGluZGl2aWR1YWwgd2hvIGlzIG91dCBvZiBzY2hvb2wgYW5kIHdvcmsgYW5kIGFsc28gaGFzIHBvb3Igc3VwcG9ydCBmcm9tIHRoZSByZWFsdGlvbnNoaXBzIG9mIG90aGVycyBtYXkgYmUgZnVydGhlciBkaXNjb25uZWN0ZWQgdGhhbiBhbiBpbmRpdmlkdWFsIHdobyBoYXMgc29jaWFsIHN1cHBvcnQuCgpIZXJlIGlzIGFuIGlsbHVzdHJhdGlvbiBvZiByaXNrIGZhY3RvcnMsIHByb3RlY3RpdmUgZmFjdG9ycyBhbmQgdGhlIGNvbnRpbnV1bSBvZiBkaXNjb25uZWN0aW9uOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjgwMCBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJyaXNrX2ZhY3RvcnMucG5nIikpCmBgYAojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzYyNDM0NDYvcGRmLzEwLjExNzdfMDAzMzM1NDkxODc5OTM0NC5wZGYpIAoKCiMjIyBTdHJhdGVnaWVzIHRvIG1pdGlnYXRlIHlvdXRoIGRpc2Nvbm5lY3Rpb24KCk1hbnkgcHJvZ3JhbXMgaGF2ZSBpZGVudGlmaWVkIHVzZWZ1bCBzdHJhdGVnaWVzIGluIHJlbmdhZ2luZyBkaXNjb25uZWN0ZWQgeW91dGggb3IgcHJldmVudGluZyBkaXNjY29uZWN0aW9uIG9mIHlvdXRoLiAKCmdlbmVyYWxseSBzcGVha2luZywgbW9zdCBwcm9ncmFtcyBmb2N1cyBvbiByZWVuZ2FnZW1lbnQgc3RyYXRlZ2llcywgaG93ZXZlciwgcHJldmVudGlvbiBzdHJhdGVnaWVzIGFyZSBsaWtlbHkgdG8gYmUganVzdCBhcyBpbXBvcnRhbnQuIAoKUmVzZXJhY2ggc3VnZ2VzdHMgdGhhdCBhY3RpdmUgaW52b2x2ZW1lbnQgd2l0aCBhdCByaXNrIHlvdXRoIGZyb20gaW5mYW5jeSBhbmQgYWNyb3NzIG11bHRpcGxlIGRldmVsb3BtZW50YWwgc3RhZ2VzIHRocm91Z2ggeW91bmcgYWR1bHRob29kIHdob3VsZCBiZSB0aGUgbW9zdCBiZW5lZmljaWFsLgoKSW4gZmFjdCwgdGhlIHF1YWxpdHkgb2YgcGFyZW50YWwgY2FyZWdpdmluZyBvZiBpbmZhbnRzIGFnZSA2LTI0IG1vbnRocyBoYXMgYWN0dWFsbHkgYmVlbiBzaG93biB0byBiZSBhIHByZWRpY3RvciBvZiBoaWdoIHNjaG9vbCBkcm9wb3V0IHJhdGVzISBUaHVzIGVhcmx5IGludGVydmVudGlvbnMgbWF5IGJlIHZlcnkgaW1wb3J0YW50IGFuZCBjb25zaXN0ZW50IGNvbnRpbnVhbCBlbmdhZ2VtZW50IG1heSBwcmV2ZW50IGZ1cnRoZXIgZGlzY29ubmVjdGlvbiBvZiB5b3V0aHMuCgpQcmV2ZW50aW9uIHN0cmF0ZWdpZXMgaW5jbHVkZTogIAoKLSBQcmVzY2hvb2wgIAotIFtUaGUgR29vZCBCZWhhdmlvciBHYW1lXShodHRwczovL3d3dy5nb29kYmVoYXZpb3JnYW1lLm9yZy9nb29kLWJlaGF2aW9yLWdhbWUtd2hhdC1pcy1pdCkgIAotIFN0cmVuZ3RoZW5pbmcgZmFtaWx5IGFuZCBjb21tdW5pdHkgY29ubmVjdGlvbnMgIAotIFByb21vdGluZyBhY2FkZW1pYyBhbmQgY2FyZWVyIGVuZ2FnZW1lbnQgIAotIExpZmUgc2tpbGxzIHRyYWluaW5nIGZvciB5b3V0aHMgYW5kIGZhbWlsaWVzICAKLSBFZHVjYXRpb24gYWJvdXQgc3Vic3RhbmNlIGFidXNlICAKLSBbQ29nbml0aXZlIGJlaGF2aW9yYWwgdGhlcmFweV0oaHR0cHM6Ly93d3cuYXBhLm9yZy9wdHNkLWd1aWRlbGluZS9wYXRpZW50cy1hbmQtZmFtaWxpZXMvY29nbml0aXZlLWJlaGF2aW9yYWwpICAgIAoKClNlZSBbaGVyZV0oaHR0cHM6Ly95b3V0aC5nb3YvZXZpZGVuY2UtaW5ub3ZhdGlvbi9wcm9ncmFtLWRpcmVjdG9yeT9rZXl3b3Jkcz0mZmllbGRfcGRfZmFjdG9yc19yaXNrc190aWQ9NDEzJmZpZWxkX3BkX2ZhY3RvcnNfcHJvdGVjdGl2ZV90aWQ9QWxsKSBhbmQgW2hlcmVdKGh0dHBzOi8vZ29jLm1hcnlsYW5kLmdvdi93cC1jb250ZW50L3VwbG9hZHMvc2l0ZXMvOC8yMDE1LzEwL1Byb2dyYW0tTW9kZWxzLWZvci1TZXJ2aW5nLU9wcG9ydHVuaXR5LVlvdXRoLnBkZikgZm9yIGxpc3RpbmdzIG9mIHByb2dyYW1zIGRlZGljYXRlZCB0byByZW5nYWdpbmcgZGlzY29ubmVjdGVkIHlvdXRoIG9yIHByZXZlbnRpbmcgZGlzY29ubmVjdGlvbi4KClNlZSBbaGVyZV0oaHR0cHM6Ly93d3cuY29tbXVuaXRpZXN0aGF0Y2FyZS5uZXQvKSBhbmQgCltoZXJlXShodHRwczovL2V4dGVuc2lvbi5wc3UuZWR1L3Byb21vdGluZy1zY2hvb2wtY29tbXVuaXR5LXVuaXZlcnNpdHktcGFydG5lcnNoaXBzLXRvLWVuaGFuY2UtcmVzaWxpZW5jZSkgZm9yIHBhcnRpY3VsYXIgZXhhbXBsZXMuCgoKVGhlIHN0YXRpc3RpY3MgdXNlZCBpbiB0aGlzIHNlY3Rpb24gY2FtZSBmcm9tIHRoaXMgW2FydGljbGVdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzYyNDM0NDYvKS4KCiMjICoqTGltaXRhdGlvbnMqKgoqKiogCgpUaGVyZSBhcmUgc29tZSBpbXBvcnRhbnQgY29uc2lkZXJhdGlvbnMgcmVnYXJkaW5nIHRoaXMgZGF0YSBhbmFseXNpcyB0byBrZWVwIGluIG1pbmQ6IAoKMSkgVGhpcyBkYXRhIHVzZWQgaW4gdGhlIFtNZWFzdXJlIG9mIEFtZXJpY2FdKGh0dHBzOi8vd3d3LnNzcmMub3JnL3Byb2dyYW1zL3ZpZXcvbW9hLykgIHByb2plY3QgcmVwb3J0cyBmcm9tIHRoZSBpcyBkZXJpdmVkIGZyb20gW0FtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkoQVNDKV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL2Fjcykgd2hpY2ggZXhjbHVkZXMgb3IgdW5kZXJyZXByZXNlbnRzIGNlcnRhaW4gb3Bwb3J0dW5pdHkgeW91dGggZ3JvdXBzLCBzdWNoIGFzIHlvdXRocyBpbiB0aGUganV2ZW5pbGUganVzdGljZSBzeXN0ZW0sIHlvdXRocyBpbiB0aGUgZm9zdGVyIGNhcmUgc3lzdGVtLCBhbmQgaG9tZWxlc3MgeW91dGhzIGFzIHRoZSBzdXJ2ZXkgaXMgY29uZHVjdGVkIG9uIGhvdXNlaG9sZHMuIEZ1cnRoZXJtb3JlLCB5b3V0aHMgd2hvIG1heSBiZSBtb3JlIGRpc2Nvbm5lY3RlZCBmb3Igb3RoZXIgcmVhc29ucyBiZXNpZGVzIG5vdCBiZWluZyBpbiB3b3JrIG9yIHNjaG9vbCwgc3VjaCBhcyBkZWFsaW5nIHdpdGggdGhlIGFkZGVkIGNoYWxsZW5nZSBvZiBiZWluZyBhIHRlZW5hZ2UgbW90aGVyLCBvciBiZWluZyBhYnVzZWQgaXMgbm90IGF2YWlsYWJsZSBpbiB0aGlzIGRhdGFzZXQuIFRodXMsIHRoaXMgZGF0YSBsaWtlbHkgdW5kZXJlc3RpbWF0ZXMgeW91dGggZGlzY29ubmVjdGlvbiByYXRlcy4gCgoyKSBEYXRhIGFib3V0IGNlcnRhaW4gZ3JvdXAgW2ludGVyc2VjdGlvbnNdKGh0dHBzOi8vd3d3LnZveC5jb20vdGhlLWhpZ2hsaWdodC8yMDE5LzUvMjAvMTg1NDI4NDMvaW50ZXJzZWN0aW9uYWxpdHktY29uc2VydmF0aXNtLWxhdy1yYWNlLWdlbmRlci1kaXNjcmltaW5hdGlvbikgKG1lYW5pbmcgZm9yIGV4YW1wbGUgaW5kaXZpZHVhbHMgb2YgYSBwYXJ0aWN1bGFyIGdlbmRlciBhbmQgZXRobmljaXR5KSBvciBwYXJ0aWN1bGFyIGdyb3VwcyBpbiBnZW5lcmFsIHN1Y2ggYXMgc3BlY2lmaWMgZXRobmljaXRpZXMgb3IgZ2VuZGVyIG9yIHNleHVhbCBpZGVudGl0eSBncm91cHMgc3VjaCBhcyBMR0JUIChsZXNiaWFuL2dheS9iaXNleHVhbC90cmFuc2dlbmRlci9xdWVlciBhbmQgcXVlc3Rpb25pbmcpIG9yIG5vbmJpbmFyeSBnZW5kZXIgcG9wdWxhdGlvbnMgaXMgdW5mb3J0dW5hdGVseSBub3QgYXZhaWxhYmxlIGluIHRoZSBkYXRhIHVzZWQgaW4gdGhpcyBhbmFseXNpcyBhbmQgaW4gbW9zdCByZXNlYXJjaCBhYm91dCB0aGlzIHRvcGljLiBMdWNraWx5IGhvd2V2ZXIsIHJlY2VudCB5ZWFycyBvZiB0aGUgW0FDUyBzdXJ2ZXldKGh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvcHJvZ3JhbXMtc3VydmV5cy9hY3MpIGhhcyBtb3JlIGRldGFpbGVkIGluZnJvbWF0aW9uIGFib3V0IGEgZ3JlYXRlciBudW1iZXIgb2YgcmFjaWFsIGFuZCBldGhuaWMgZ3JvdXBzIGFuZCByYWNpYWwvZXRobmljIGludGVyc2VjdGlvbnMuCgozKSBUaGUgc3RhdGlzdGljYWwgcHJvY2VkdXJlcyB3ZSBhcmUgdXNpbmcgbWF5IGJlIG92ZXJseSBzaW1wbGlzdGljLiAqSW4gYWxsIGRhdGEgYW5hbHlzaXMsIHdlIG5lZWQgdG8gYmUgd2FyeSBhYm91dCBkZXJpdmluZyBtZWFuaW5nIGZyb20gdGhlIHN0YXRpc3RpY2FsIHByb2NlZHVyZXMgd2UgdXNlKi4KCjQpIFVzaW5nIGltYWdlIHByb2Nlc3NpbmcgdG9vbHMgY2FuIGJlIHZlcnkgaGVscGZ1bC4gVGhlIG1hbm5lciBpbiB3aGljaCBkYXRhIGlzIG9idGFpbmVkIHdpdGggaW1hZ2UgcHJvY2Vzc2luZyB0b29scyBpcyB3aGF0IHdlIHdvdWxkIGRlc2NyaWJlIGFzIGEgKipibGFjayBib3ggcHJvY2VzcyoqLCA8dT4qYSBwcm9jZXNzIHdpdGgga25vd24gaW5wdXRzIGFuZCBvdXRwdXRzIGJ1dCB1bmtub3duIG1lY2hhbmljcyo8L3U+LiBCZWNhdXNlIHdlIGFyZSB1bmF3YXJlIG9mIGhvdyBvdXIgb3V0cHV0cyBhcmUgZ2VuZXJhdGVkIGZyb20gb3VyIGlucHV0cywgd2UgbmVlZCB0byBiZSB3YXJ5IG9mIHRoZSBvdXRwdXQuIFdpdGggdGhlIHNtYWxsIG91dHB1dCB3ZSBhcmUgY3JlYXRpbmcgaW4gdGhpcyBjYXNlIHN0dWR5LCBhIHZpc3VhbCBpbnNwZWN0aW9uIHNob3VsZCBzdWZmaWNlLiAKCgojIyAqKldoYXQgYXJlIHRoZSBkYXRhPyoqCioqKiAKCkluIHRoaXMgY2FzZSBzdHVkeSB3ZSB3aWxsIGJlIHVzaW5nIGRhdGEgcmVsYXRlZCB0byB5b3V0aCBkaXNjb25uZWN0aW9uIGZyb20gdGhlIHR3byBmb2xsb3dpbmcgcmVwb3J0cyBmcm9tIHRoZSBbTWVhc3VyZSBvZiBBbWVyaWNhXShodHRwczovL3d3dy5zc3JjLm9yZy9wcm9ncmFtcy92aWV3L21vYS8pICBwcm9qZWN0OgoKPiBNZWFzdXJlIG9mIEFtZXJpY2EgaXMgYSBub25wYXJ0aXNhbiBwcm9qZWN0IG9mIHRoZSBub25wcm9maXQgW1NvY2lhbCBTY2llbmNlIFJlc2VhcmNoIENvdW5jaWxdKGh0dHBzOi8vd3d3LnNzcmMub3JnLykgIGZvdW5kZWQgaW4gMjAwNyB0byBjcmVhdGUgZWFzeS10by11c2UgeWV0IG1ldGhvZG9sb2dpY2FsbHkgc291bmQgdG9vbHMgZm9yIHVuZGVyc3RhbmRpbmcgd2VsbC1iZWluZyBhbmQgb3Bwb3J0dW5pdHkgaW4gQW1lcmljYS4gVGhyb3VnaCByZXBvcnRzLCBpbnRlcmFjdGl2ZSBhcHBzLCBhbmQgY3VzdG9tLWJ1aWx0IGRhc2hib2FyZHMsIE1lYXN1cmUgb2YgQW1lcmljYSB3b3JrcyB3aXRoIHBhcnRuZXJzIHRvIGJyZWF0aGUgbGlmZSBpbnRvIG51bWJlcnMsIHVzaW5nIGRhdGEgdG8gaWRlbnRpZnkgYXJlYXMgb2YgaGlnaGVzdCBuZWVkLCBwaW5wb2ludCBsZXZlcnMgZm9yIGNoYW5nZSwgYW5kIHRyYWNrIHByb2dyZXNzIG92ZXIgdGltZS4KCjEuIExld2lzLCBLcmlzdGVuLiBbTWFraW5nIHRoZSBDb25uZWN0aW9uOiBUcmFuc3BvcnRhdGlvbiBhbmQgWW91dGggRGlzY29ubmVjdGlvbl0oaHR0cHM6Ly9zc3JjLXN0YXRpYy5zMy5hbWF6b25hd3MuY29tL21vYS9NYWtpbmclMjB0aGUlMjBDb25uZWN0aW9uLnBkZikgLiBOZXcgWW9yazogTWVhc3VyZSBvZiBBbWVyaWNhLCBTb2NpYWwgU2NpZW5jZSBSZXNlYXJjaCBDb3VuY2lsLCAyMDE5LiAgKERhdGEgdXAgdG8gMjAxNykKCmBgYHtyLCBvdXQud2lkdGg9IjQwMHB4IiwgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiTWFraW5nX3RoZV9Db25uZWN0aW9uLnBuZyIpKQpgYGAKCjIuIDogTGV3aXMsIEtyaXN0ZW4uIFtBIERlY2FkZSBVbmRvbmU6IFlvdXRoIERpc2Nvbm5lY3Rpb24gaW4gdGhlIEFnZSBvZiBDb3JvbmF2aXJ1c10oaHR0cHM6Ly9zc3JjLXN0YXRpYy5zMy5hbWF6b25hd3MuY29tL21vYS9BRGVjYWRlVW5kb25lLnBkZikuIE5ldyBZb3JrOiBNZWFzdXJlIG9mIEFtZXJpY2EsIFNvY2lhbCBTY2llbmNlIFJlc2VhcmNoIENvdW5jaWwsIDIwMjAuIChEYXRhIHVwIHRvIDIwMTgpCgpgYGB7ciwgb3V0LndpZHRoPSI0MDBweCIsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIkFfRGVjYWRlX1VuZG9uZS5wbmciKSkKYGBgCgpUaGUgZGF0YSB1c2VkIGluIHRoZXNlIHJlcG9ydHMgY29tZXMgZnJvbSB0aGUgW0FtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkoQVNDKV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL2FjcyksIHdoaWNoIGlzIHRoZSBsYXJnZXN0IHN1cnZleSBjb25kdWN0ZWQgYnkgdGhlIFVuaXRlZCBTdGF0ZXMgQ2Vuc3VzIEJ1cmVhdS4gVGhlIHN1cnZleSBzdGFydGVkIGluIDIwMDUgYW5kIGNvbGxlY3RzIGRhdGEgZm9yIDMuNSBtaWxsaW9uIGhvdXNlaG9sZHMgYW5udWFsbHkuIERhdGEgaXMgY29sbGVjdGVkIGFib3V0IGFuY2VzdHJ5LCBjaXRpemVoc2lwLCBpbmNvbWUsIGVtcGxveW1lbnQsIGRpc2FiaWxpdHkgYW1vbmcgbWFueSBvdGhlciBhc3BlY3RzLiBTZWUgW2hlcmVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0FtZXJpY2FuX0NvbW11bml0eV9TdXJ2ZXkpIGZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uIGFib3V0IHRoZSBzdXJ2ZXkuCgpBY2NvcmRpbmcgdG8gV2lraXBlZGlhIChodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BbWVyaWNhbl9Db21tdW5pdHlfU3VydmV5KToKCj4gRGF0YSBpcyBjb2xsZWN0ZWQgYnkgaW50ZXJuZXQsIG1haWwsIHRlbGVwaG9uZSBpbnRlcnZpZXdzIGFuZCBpbi1wZXJzb24gaW50ZXJ2aWV3cy4uLkFib3V0IDk1IHBlcmNlbnQgb2YgaG91c2Vob2xkcyBhY3Jvc3MgYWxsIHJlc3BvbnNlIG1vZGVzIHVsdGltYXRlbHkgcmVzcG9uZC4uLiBBQ1MgcmVzcG9uc2VzIGFyZSBjb25maWRlbnRpYWwuLi4gYW5kICJpbW11bmUgZnJvbSBsZWdhbCBwcm9jZXNzIgoKPiBJdCBpcyBhIG1hbmRhdG9yeSBzdXJ2ZXksIGl0IGlzIGdvdmVybmVkIGJ5IGZlZGVyYWwgbGF3cyB0aGF0IGNvdWxkIGltcG9zZSBhIGZpbmUgb2YgYXMgbXVjaCBhcyAkNSwwMDAgZm9yIHJlZnVzaW5nIHRvIHBhcnRpY2lwYXRlLgoKCldlIGFyZSBwYXJ0aWN1bGFybGx5IGludGVyZXNlZCBpbiB0aGUgZm9sbG93aW5nIHRhYmxlcyBvbiB0aGUgbGFzdCBwYWdlIG9mIHRoZSBbTWVhc3VyZSBvZiBBbWVyaWNhIDIwMTkgcmVwb3J0XShodHRwczovL3NzcmMtc3RhdGljLnMzLmFtYXpvbmF3cy5jb20vbW9hL01ha2luZyUyMHRoZSUyMENvbm5lY3Rpb24ucGRmKToKCmBgYHtyLCBlY2hvID0gRkFMU0UsIGdlbmRlcl9yYWNlX2V0aF8yMDE5fQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiZ2VuZGVyX3JhY2VfZXRobmljaXR5X292ZXJ2aWV3LnBuZyIpKQpgYGAKCldlIGFyZSBwYXJ0aWN1bGFybGx5IGludGVyZXNlZCBpbiB0aGUgdGFibGVzIG9uIHRoZSBmb2xsb3dpbmcgcGFnZXMgZnJvbSB0aGUgW01lYXN1cmUgb2YgQW1lcmljYSAyMDIwIHJlcG9ydF0oaHR0cHM6Ly9zc3JjLXN0YXRpYy5zMy5hbWF6b25hd3MuY29tL21vYS9BRGVjYWRlVW5kb25lLnBkZik6CgoKYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImxhdGlueF8yMDE4X292ZXJ2aWV3LnBuZyIpKQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJhc2lhbl8yMDE4X292ZXJ2aWV3LnBuZyIpKQpgYGAKCgoKIyMgKipEYXRhIEltcG9ydCoqCioqKiAKCk9uZSB3YXkgdG8gaW1wb3J0IGRhdGEgZnJvbSBhIHBkZiBpcyB0byB1c2UgdGhlIGBwZGZfdGV4dCgpYCBmdW5jdGlvbiBvZiB0aGUgYHBkZnRvb2xzYCBwYWNrYWdlLiBUaGUgYGhlcmUoKWAgZnVuY3Rpb24gb2YgdGhlIGBoZXJlYCBwYWNrYWdlIGNhbiBhbGxvdyB1cyB0byBzcGVjaWZ5IHdoZXJlIHRoZSBkb2N1bWVudCB0aGF0IHdlIHdhbnQgdG8gaW1wb3J0IGlzIGxvY2F0ZWQgZWFzaWx5LCBzdGFydGluZyBmcm9tIHRoZSBkaXJlY3Rvcnkgd2hlcmUgYSBgLlJwcm9qYCBmaWxlIGlzIGxvY2F0ZWQuIEluIHRoaXMgY2FzZSwgd2Ugd2lsbCBpbXBvcnQgdGhlIGBNYWtpbmdfdGhlX0Nvbm5lY3Rpb24ucGRmYCBpbiB0aGUgYGRvY3NgIGRpcmVjdG9yeS4gKk5vdGUgdGhpcyBpcyB0aGUgY2FzZSBpZiB5b3UgcHVsbCB0aGUgcmVwb3NpdG9yeSBmcm9tIGdpdGh1Yi4qCgpgYGB7cn0KcGRmX3Rvb2xzX2V4YW1wbGUgPC0gcGRmdG9vbHM6OnBkZl90ZXh0KGhlcmU6OmhlcmUoImRvY3MiLCJNYWtpbmdfdGhlX0Nvbm5lY3Rpb24ucGRmIikpCmBgYAoKV2UgY2FuIHRha2UgYSBsb29rIGF0IHRoZSBvdXRwdXQgZm9yIHRoZSBwYWdlIHdpdGggb3VyIHRhYmxlIG9mIGludGVyZXN0cyBieSBzaW1weSB1c2luZyBicmFja2V0cyBgW11gIGFyb3VuZCB0aGUgcGFnZSBudW1iZXIuIFRoZSBwYWdlIHdlIGFyZSBpbnRlcmVzdGVkIGluIChhdGhvdWdoIGNhbGxlZCAzOSBpbiB0aGUgcmVwb3J0KSBpcyB0aGUgNDR0aCBwYWdlLCB3aGljaCBsb29rcyBsaWtlIHRoaXM6CgpgYGB7ciwgZ2VuZGVyX3JhY2VfZXRoXzIwMTksIGVjaG89RkFMU0V9CmBgYAoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpwZGZfdG9vbHNfZXhhbXBsZVs0NF0KYGBgCiMjIyMKCkZyb20gdGhlIG91dHB1dCwgaXQncyBjbGVhciB0aGF0IGEgcmVsYXRpdmVseSBsYXJnZSBhbW91bnQgb2YgbWFuaXB1bGF0aW9uIHdpbGwgYmUgcmVxdWlyZWQgdG8gd3JhbmdsZSB0aGlzIGRhdGEuIElmIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiBsZWFybmluZyBtb3JlIGFib3V0IHRoaXMgbWV0aG9kLCBwbGVhc2Ugc2VlIHRoaXMgW2Nhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtcnVyYWwtYW5kLXVyYmFuLW9iZXNpdHkvKSBhbmQgdGhpcyBbY2FzZSBzdHVkeV0oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL29jcy1icC1ydXJhbC1hbmQtdXJiYW4tb2Jlc2l0eS8pLgoKV2hpbGUgbm90IGltcG9zc2libGUsIHVzaW5nIHRoZSBgcGRmdG9vbHNgIHBhY2thZ2UgaW4gdGhpcyBzY2VuYXJpbyB3aWxsIGJlIGEgYml0IGNoYWxsZW5naW5nIGJlY3Vhc2Ugb2YgaG93IHRoZSBtdWx0aXBsZSB0YWJsZXMgYXJlIGRpc3BsYXllZCBvbiB0aGlzIHBhZ2UuCgpXaGlsZSBvdXIgb3V0cHV0IG1heSBiZSByZXByb2R1Y2libGUsIHRoaXMgcHJvY2VzcyBtYXkgYmUgdG9vIHRpbWUgY29uc3VtaW5nLgoKRm9ydHVuYXRlbHksIHRoZXJlIGlzIGFub3RoZXIgd2F5IHdlIGNhbiBwcm9jZWVkIHRvIHdyYW5nbGUgdGhlIGRhdGEuIAoKV2Ugd2lsbCBkZW1vbnN0cmF0ZSBob3cgdG8gcHJvZHVjZSByZXByb2R1Y2libGUgdGFibGVzIHdpdGggaW1hZ2UgcHJvY2Vzc2luZyBzb2Z0d2FyZSBpbiBgUmAgdXNpbmcgIGEgcGFja2FnZSBjYWxsZWQgYG1hZ2lja2Agd2hpY2ggYWxsb3dzIGZvciB0aGUgZXh0cmFjdGlvbiBvZiB0ZXh0IGZyb20gaW1hZ2VzLiBUaGUgYWR2YW50YWdlIG9mIHRoaXMgb3B0aW9uLCBpcyB0aGF0IHdlIGNhbiB0YWtlIGEgc2NyZWVuc2hvdCBvZiBqdXN0IGEgcGllY2Ugb2YgdGhlIHBhZ2UgdG8gd3JhbmdsZS4gCgpGb3IgZGVtb25zdHJhdGl2ZSBwdXJwb3Nlcywgd2Ugd2lsbCBpbXBvcnQgdHdvIHNldHMgb2YgZGF0YS4gVGhlIGZpcnN0IHNldCBvZiBkYXRhIHdpbGwgYmUgdXNlZCB0byBoaWdobGlnaHQgY29tbW9uIGVycm9ycyB0aGF0IHRoZSBpbWFnZSBwcm9jZXNzaW5nIHNvZnR3YXJlIG1heSBwcm9kdWNlLiBUaGUgc2Vjb25kIHNldCBvZiBkYXRhIHdpbGwgYmUgdXNlZCB0byBkZW1vbnN0cmF0ZSBob3cgdG8gY2lyY3VtdmVudCB0aGVzZSBlcnJvcnMgYW5kIHByb2R1Y2UgcmVwcm9kdWNpYmxlIGRhdGFzZXRzIGVmZmljaWVudGx5LgoKCiMjIyBJbXBvcnRpbmcgd2l0aCBgbWFnaWNrYAoKV2Ugd2lsbCBub3cgaW1wb3J0IHRoZSBkYXRhIHVzaW5nIHRoZSBgbWFnaWNrYCBwYWNrYWdlIHdoaWNoIGFsbG93cyBmb3IgdGhlIGltcHJvdGF0aW9uIG9mIGltYWdlcy4gCgpGaXJzdCB3ZSB3aWxsIHRha2UgYSBzY3JlZW5zaG90IG9mIHRoZSB0b3AgcGFydCBvZiB0aGUgZ2VuZGVyLCByYWNlLCBhbmQgZXRobmljaXR5IHRhYmxlIG9uIHRoZSBsYXN0IHBhZ2Ugb2YgdGhlIFsyMDE5IE1lYXN1cmUgb2YgQW1lcmljYSBSZXBvcnRdKGh0dHBzOi8vc3NyYy1zdGF0aWMuczMuYW1hem9uYXdzLmNvbS9tb2EvTWFraW5nJTIwdGhlJTIwQ29ubmVjdGlvbi5wZGYpLiBXZSBhcmUgb25seSBpbnRlcmVzdGVkIGluIHRoZSBwZXJjZW50YWdlIG9mIGRpc2Nvbm5lY3Rpb24gYWNyb3NzIHRoZSB5ZWFycywgc28gd2UgZG9udCBuZWVkIG91ciBzY3JlZW5zaG90IHRvIGluY2x1ZGUgdGhlIGxhc3QgY291cGxlIG9mIGNvbHVtbnMuCgpXZSBjYW4gc2hvdyB3aGF0IHRoaXMgZmlsZSBsb29rcyBsaWtlIGluIHRoaXMgcmVuZGVyZWQgcm1hcmtkb3duIHdlYnNpdGUgYnkgdXNpbmcgdGhlIGBpbmNsdWRlX2dyYXBoaWNzKClgIGZ1bmN0aW9uIG9mIHRoZSBga25pdHJgIHBhY2thZ2UuCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIk1ham9yX2V0aG5pY19ncm91cHNfc2NyZWVuc2hvdC5wbmciKSkKYGBgCgpOb3csIHdlIHdpbGwgdXNlIHRoZSBgaW1hZ2VfcmVhZCgpYCBmdW5jdGlvbiBvZiB0aGUgYG1hZ2lja2AgcGFja2FnZSB0byBpbXBvcnQgdGhpcyBpbWFnZS4KCldlIGNhbiB0aGVuIHVzZSB0ZWggYGltYWdlX2luZm8oKWAgZnVuY3Rpb24gdG8gbWFrZSBzdXJlIHRoYXQgdGhlIGltcG9ydCB3b3JrZWQgYW5kIHRvIGdldCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgc2l6ZSwgZm9ybWF0IGFuZCBjb2xvciBvZiB0aGUgaW1hZ2UuCgpgYGB7ciwgZHBpID0gMTAwMH0KTWFqb3JfcmFjaWFsX2V0aG5pY19ncm91cHMgPC0gbWFnaWNrOjppbWFnZV9yZWFkKGhlcmU6OmhlcmUoImltZyIsICJNYWpvcl9ldGhuaWNfZ3JvdXBzX3NjcmVlbnNob3QucG5nIikpCgptYWdpY2s6OmltYWdlX2luZm8oTWFqb3JfcmFjaWFsX2V0aG5pY19ncm91cHMpCmBgYApOb3cgbGV0J3MgdGFrZSBhIGxvb2sgYXQgb3VyIGltYWdlIGluIFIhIE5vdyB0aGF0IHdlIGhhdmUgaW1wb3J0ZWQgaXQgdG8gc2VlIHRoaXMgaW1hZ2UsIHdlIHNpbXBseSBuZWVkIHRvIHR5cGUgdGhlIG5hbWUgb2YgdGhlIGltYWdlLgoKYGBge3J9Ck1ham9yX3JhY2lhbF9ldGhuaWNfZ3JvdXBzCmBgYAoKTmljZSEKCgpMZXQncyBhIGNvdXBsZSBtb3JlIGltYWdlcyBqdXN0IGZvciBmdW4uIEhlcmUgd2Ugd2lsbCBpbXBvcnQgYW4gaW1hZ2UgZGlyZWN0bHkgZnJvbSBhIFVSTC4KCmBgYHtyLCBvdXQud2lkdGg9IjIwJSJ9CmdncGxvdDJfbG9nbyA8LSBpbWFnZV9yZWFkKCJodHRwczovL2QzM3d1YnJma2kwbDY4LmNsb3VkZnJvbnQubmV0LzJjNjIzOWQzMTFiZTZkMDM3YzI1MWM3MWMzOTAyNzkyZjhjNGRkZDIvMTJmNjcvY3NzL2ltYWdlcy9oZXgvZ2dwbG90Mi5wbmciKQpnZ3Bsb3QyX2xvZ28KYGBgCgpOb3cgd2Ugd2lsbCB1c2UgdGhlIGBpbWFnZV9vY3IoKWAgZnVuY3Rpb24gb2YgdGhlIGBtYWdpY2tgIHBhY2thZ2UgdG8gZXh0cmFjdCB0aGUgdGV4dCBmcm9tIHRoZSBPQ1MgbG9nbyBpbWFnZS4gVGhpcyBmdW5jdGlvbiB1c2VzIHRoZSBgdGVzc2VyYWN0YCBwYWNrYWdlIHdoaWNoIGhhcyB0b29scyBmb3IgW29wdGljYWwgY2hhcmFjdGVyIHJlY29nbml0aW9uIChPQ1IpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9PcHRpY2FsX2NoYXJhY3Rlcl9yZWNvZ25pdGlvbiksIGhlbmNlIHRoZSBgb2NyYCBpbiB0aGUgZnVuY3Rpb24gbmFtZS4gVGhpcyBhbGxvd3MgdGhlIGZ1bmN0aW9uIHRvIGlkZW50aWZ5IHRleHQgaW4gaW1hZ2VzLiBUaGVzZSBPQ1IgdG9vbHMgaGF2ZSBvZnRlbiBiZWVuIGRldmVsb3BlZCB1c2luZyBbbWFjaGluZSBsZWFybmluZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTWFjaGluZV9sZWFybmluZykgaW4gd2hpY2ggYW4gYWxnb3JpdGhtIHdhcyB0cmFpbmVkIG9uIGltYWdlcyB3aXRoIGFuZCB3aXRob3V0IHRleHQgdG8gImxlYXJuIiB0byByZWNvZ25pemUgdGV4dC4gU2VlIFtoZXJlXShodHRwczovL3Rvd2FyZHNkYXRhc2NpZW5jZS5jb20vYS1nZW50bGUtaW50cm9kdWN0aW9uLXRvLW9jci1lZTE0NjlhMjAxYWEpIHRvIGxlYXJuIG1vcmUgYWJvdXQgaG93IE9DUiB3b3Jrcy4KCmBgYHtyfQptYWdpY2s6OmltYWdlX29jcihnZ3Bsb3QyX2xvZ28pCmBgYAoKQXdlc29tZSEgV2Ugd2VyZSBhYmxlIHRvIGV4dHJhY3QgdGV4dCBmcm9tIHRoaXMgaGV4IHN0aWNrZXIhCgpPbmUgdGhpbmcgdG8ga2VlcCBpbiBtaW5kIGlzIHRoYXQgdGhpcyBkb2Vzbid0IGFsd2F5cyB3b3JrLiBVbnVzdWFsIGZvbnQsIGFuZ2xlcyB0ZXh0LCBvciBwYXJ0aWN1bGFyIGNvbG9ycyBjYW4gYmUgZGlmZmljdWx0IGZvciB0aGUgT0NSIHRvIHJlY29naW5pemUuCgpIZXJlIGlzIGFuIGV4YW1wbGUgdGhhdCBkb2VzIG5vdCB3b3JrIHdpdGggdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiBgbWFnaWNrYDoKCmBgYHtyLCBvdXQud2lkdGg9IjIwJSJ9CnRpZHl2ZXJzZV9sb2dvIDwtIGltYWdlX3JlYWQoImh0dHBzOi8vdGlkeXZlcnNlLnRpZHl2ZXJzZS5vcmcvbG9nby5wbmciKQp0aWR5dmVyc2VfbG9nbwptYWdpY2s6OmltYWdlX29jcih0aWR5dmVyc2VfbG9nbykKYGBgCgpUaGlzIGlzIGxpa2VseSBkbyB0byB0aGUgYmFja2dyb3VuZCBvbiB0aGlzIHBhcnRpY3VsYXIgaGV4IHN0aWNrZXIuIFNvIHNvbWV0aW1lcyB0aGlzIHByb2Nlc3MgcmVxdWlyZXMgYSBiaXQgb2YgdHJpYWwgYW5kIGVycm9yLgoKIyMgKipEYXRhIFdyYW5nbGluZyoqCioqKiAKTm93IGxldCdzIHRyeSBleHRyYWN0aW5nIHRoZSB0ZXh0IGZyb20gb3VyIGltYWdlIGZpbGVzLgoKIyMjIE1ham9yIFJhY2lhbCBhbmQgRXRobmljIEdyb3VwcwoKVGhlIGZpcnN0IGltYWdlIHdlIGltcG9ydGVkIGxvb2tzIGxpa2UgdGhpcy4gCgpgYGB7cn0KTWFqb3JfcmFjaWFsX2V0aG5pY19ncm91cHMKYGBgCgpOb3cgd2Ugd2lsbCBleHRyYWN0IHRoZSB0ZXh0ISAKCmBgYHtyfQptYWpvcl9ncm91cHMgPC0gbWFnaWNrOjppbWFnZV9vY3IoTWFqb3JfcmFjaWFsX2V0aG5pY19ncm91cHMpCm1ham9yX2dyb3VwcwpgYGAKVGhpcyBsb29rcyBsaWtlIGl0IHdvcmtlZCBmYWlybHkgd2VsbCEKCldlIGFwcGVhciB0byBoYXZlIGxvc3QgdGhlIGNvbHVtbiBuYW1lcyBidXQgdGhlIHZhbHVlcyBsb29rIHByZXR0eSBnb29kLgoKWW91IG1heSBub3RpY2UgdGhhdCB0aGVyZSBhcmUgbG90cyBvZiBgXG5gIHZhbHVlcyBpbiB0aGUgdGV4dCBmcm9tIG91ciBpbWFnZS4gVGhlc2UgYXJlIFsqKm5ld2xpbmUqKl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTmV3bGluZT9vbGRmb3JtYXQ9dHJ1ZSkgY2hhcmFjdGVycywgd2hpY2ggZGVub3RlIHRoZSBlbmQgb2YgYSBsaW5lIG9mIHRleHQgYW5kIHRoZSBzdGFydCBvZiBhIG5ldyBsaW5lIG9mIHRleHQuICAKCldlIGNhbiB1c2UgdGhlIGBzdHJfc3BsaXQoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlIHRvIHNwbGl0IGJhc2VkIG9uIHRoZSBgXG5gIGNoYXJhY3RlcnMgaW4gdGhlIG91dHB1dC4gV2Ugd2lsbCB0aGVuIHVubGlzdCB0aGUgb3V0cHV0IHVzaW5nIHRoZSBiYXNlIFIgYHVubGlzdCgpYCBmdW5jdGlvbi4gQnkgYmFzZSwgd2UgbWVhbiB0aGF0IHRoZSBmdW5jdGlvbiBpdCBpcyBsb2FkZWQgYXV0b21hdGljYWxseSBpbiBhbiBSIHNlc3Npb24uIEZpbmFsbHkgd2Ugd2lsbCB1c2UgdGhlIGBhc190aWJibGUoKWAgZnVuY3Rpb24gb2YgdGhlIGB0aWJibGVgIHBhY2thZ2UgdG8gY29udmVydCB0aGUgZGF0YSBpbnRvIFt0aWJibGVdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvKSBmb3JtYXQsIHdoaWNoIGlzIHRoZSB0aWR5dmVyc2UgdmVyc2lvbiBvZiBhIGRhdGEgZnJhbWUuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBzZWUgdGhlIHZhbHVlcyBpbiB0aGUgdGFibGUgbXVjaCBiZXR0ZXIuCgpUbyBkbyBhbGwgb2YgdGhlc2Ugc2VxdWVudGlhbCBzdGVwcyBlZmZpY2llbnRseSB3ZSB3aWxsIHVzZSBhIG1ldGhvZCBjYWxsZWQgcGlwaW5nLgoKKioqCjxkZXRhaWxzPiA8c3VtbWFyeT5DbGljayBoZXJlIGlmIHlvdSBhcmUgdW5mYW1pbGlhciB3aXRoIHBpcGluZyBpbiBSLCB3aGljaCB1c2VzIHRoaXMgYCU+JWAgb3BlcmF0b3IuPC9zdW1tYXJ5PiAgCgpCeSBbcGlwaW5nXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFncml0dHIvdmlnbmV0dGVzL21hZ3JpdHRyLmh0bWwpIHdlIG1lYW4gdXNpbmcgdGhlIGAlPiVgIHBpcGUgb3BlcmF0b3Igd2hpY2ggaXMgYWNjZXNzaWJsZSBhZnRlciBsb2FkaW5nIHRoZSBgdGlkeXZlcnNlYCBvciBzZXZlcmFsIG9mIHRoZSBwYWNrYWdlcyB3aXRoaW4gdGhlIHRpZHl2ZXJzZSBsaWtlIGBkcGx5cmAgYmVjYXVzZSB0aGV5IGxvYWQgdGhlIFtgbWFncml0dHJgIHBhY2thZ2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdyaXR0ci92aWduZXR0ZXMvbWFncml0dHIuaHRtbCkuIApUaGlzIGFsbG93cyB1cyB0byBwZXJmb3JtIG11bHRpcGxlIHNlcXVlbnRpYWwgc3RlcHMgb24gb25lIGRhdGEgaW5wdXQuICAgCjwvZGV0YWlscz4gIAoqKioKCmBgYHtyfQogbWFqb3JfZ3JvdXBzIDwtIG1ham9yX2dyb3VwcyAlPiUKICBzdHJpbmdyOjpzdHJfc3BsaXQocGF0dGVybiA9IlxuIikgJT4lCiAgdW5saXN0KCkgJT4lCiAgdGliYmxlOjphc190aWJibGUoKQpgYGAKCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQogIAogIG1ham9yX2dyb3VwcyAlPiVwcmludChuID0gMjApCgpgYGAKIyMjIwoKCk9LLCB0aGlzIGxvb2tzIHByZXR0eSBnb29kIQoKVGhlIG9ubHkgaXNzdWUgaXMgdGhhdCBzb21lIHZhbHVlcyBhcHBlYXIgdG8gYmUgbWlzc2luZyBhIGRlY2ltYWwgcG9pbnQuIAoKTm8gd29ycmllcyB0aG91Z2gsIHdlIGNhbiBtb2RpZnkgdGhlIGVudGlyZSB0YWJsZSBpbiBhIHJlcHJvZHVjYmlsZSB3YXkgdG8gZ2V0IHRob3NlIGRlY2ltYWwgcGxhY2VzIGJhY2suIEhvd2V2ZXIsIGZpcnN0IHdlIG5lZWQgdG8gZG8gc29tZSBvdGhlciB3cmFuZ2xpbmcgc3RlcHMgZmlyc3QuCgpGaXJzdCwgbGV0J3Mgc3BlYXJhdGUgdGhlIGZpcnN0IGNvbHVtbiBhYm91dCBldGhuaWNpdGllcyB3aXRoIHRoZSB2YWx1ZXMgaW4gdGhlIHN1YnNlcXVlbnQgY29sdW1ucy4gV2UgY2FuIGRvIHNvIHVzaW5nIHRoZSBgc2VwYXJhdGUoKWAgZnVuY3Rpb24gb2YgdGhlIGB0aWR5cmAgcGFjYWtnZSBiYXNlZCBvbiBbcmVndWxhciBleHByZXNzaW9uc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmVndWxhcl9leHByZXNzaW9uKS4gUmVndWxhciBleHByZXNzaW9ucyAoYWJicmV2aWF0ZWQgcmVnZXgpIGFyZSBub3RhdGlvbiBzaG9ydGN1dHMgdGhhdCBkZXNjcmliZSBwYXR0ZXJucyBpbiBjaGFyYWN0ZXIgc3RyaW5ncy4gU2VlIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby9jaGVhdHNoZWV0cy9yYXcvbWFzdGVyL3N0cmluZ3MucGRmKSBmb3IgYW4gUlN0dWRpbyBjaGVldHNoZWF0IGFib3V0IHRoZW0uCgpXZSB3YW50IHRvIHNlcGFyYXRlIGJ5IGluc3RhbmNlcyB3aGVyZSBhIGxldHRlciBpcyBmb2xsb3dlZCBieSBhIHNwYWNlIGFuZCB0aGVuIGEgbnVtYmVyLiAKCldlIGNhbiBzcGVjaWZ5IGFueSBsZXR0ZXIgYnkgdXNpbmcgdGhlIHJlZ2V4IGBbOmFscGhhOl1gIG5vdGF0aW9uIGFuZCBhbnkgbnVtYmVyIGJ5IHVzaW5nIHRoZSByZWdleCBgWzpkaWdpdF1gIG5vdGF0aW9uLiBXZSBjb3VsZCBoYXZlIGxpc3RlZCBldmVyeSBsZXR0ZXIgdGhhdCB3ZSBzYXcgdGhlIGZpcnN0IGNvbHVtbiBlbmRpbmcgd2l0aCBsaWtlIHNvIGBzfGV8RXxPfEt8TmAgYnV0IHRoaXMgd291bGQgbm90IGJlIGFzIHJlcHJvZHVjaWJsZSAobWVhbmluZyBtYXliZSB0aGlzIHdvdWxkIG5vdCB3b3JrIGFzIHdlbGwgbmV4dCB5ZWFyIGlmIGEgbmV3IGdyb3VwIHdlcmUgYWRkZWQgdGhhdCBlbmRlZCBpbiBhIGRpZmZlcmVudCBsZXR0ZXIpLCBhbmQgd2UgbWlnaHQgbWFrZSBhIG1pc3Rha2UuIFRoaXMgaXMgd2h5IHRoZSByZWdleCBhcmUgc28gdXNlZnVsLiAKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0gIjQwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJhbHBoYS5wbmciKSkKYGBgCldlIGNhbiBpbmRpY2F0ZSB0aGF0IHdlIHdhbnQgYSBzcGFjZSBieSB1c2luZyB0aGlzIHJlZ2V4OgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSAiNDAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInJlZ2V4LnBuZyIpKQpgYGAKCgpOb3cgdG8gc3BlY2lmeSB0aGF0IHdlIHdhbnQgdG8gc2VlIGEgbGV0dGVyIGZpcnN0IGZvbGxvd2VkIGJ5IGEgc3BhY2UsIGZvbGxvd2VkIGJ5IGEgZGlnaXQsIHdlIG5lZWQgdG8gdXNlIGEgbG9vayBhcm91bmQ6IAoKYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImxvb2tfYXJvdW5kLnBuZyIpKQpgYGAKCldlIHdpbGwgdXNlIHRoZSAicHJlY2VkZWQgYnkiIGFuZCAiZm9sbG93ZWQgYnkiIGxvb2sgYXJvdW5kcy4gVGh1cyBgKD88PVs6YWxwaGE6XSlgIHN0YW5kcyBmb3IgYW55IGxldHRlciB0aGF0IGFwcGVhcnMgYmVmb3JlIGEgc3BhY2UgYFxcc2AgdGhhdCBpcyBmb2xsb3dlZCBieSBhbnkgZGlnaXQgYCg/PVswLTldKWAuIEFsdG9nZXRoZXIgdGhlIHBhdHRlcm4gd2Ugd2FudCB0byBzZXBhcmF0ZSBieSBsb29rcyBsaWtlIHRoaXM6IGAiKD88PVs6YWxwaGE6XSlcXHMoPz1bMC05XSkiYC4KCgpOb3cgdG8gc2VwYXJhdGUgdGhlIHZhbHVlIGNvbHVtbiBpbnRvIHR3byBjbG91bW5zLCB3ZSBjYW4gdXNlIHRoZSBgc2VwYXJhdGVgIGZ1bmN0aW9uIG9mIHRoZSBgdGlkeXJgIHBhY2FrZ2UgdG8gZG8gdGhpcy4gVGhpcyB3aWxsIGFsbG93IHVzIHRvIG5vdCBvbmx5IHNwbGl0IHRoZSByb3dzIGJ5IG91ciByZWdleCBleHByZXNzaW9uLCBidXQgYWxzbyB0byBjcmVhdGUgY29sdW1uIG5hbWVzLgoKVGhlcmUgYXJlIHRocmVlIGltcG9ydGFudCBhcmd1bWVudHMgZm9yIHRoZSBgc2VwZXJhdGUoKWAgZnVuY3Rpb246ICAKLSBgY29sYCAtIHRoaXMgc3BlY2lmaWVzIHdoYXQgY29sdW1uIHlvdSBhcmUgc2VwYXJhdGluZyAgIAotIGBpbnRvYCAtIHRoaXMgc3BlY2lmaWVzIHRoZSBuYW1lcyBvZiB0aGUgbmV3IGNvbHVtbnMgeW91IGFyZSBjcmVhdGluZyAgCi0gYHNlcGAgLSB0aGlzIHNwZWNpZmllcyB3aGF0IGNoYXJhY3RlciBzdHJpbmcgdG8gbG9vayBmb3IgdG8gc2VwYXJhdGUgYnkgIAoKVGh1cyB3ZSB3aWxsIHNlcGFyYXRlIHRoZSBgdmFsdWVgIGNvbHVtbiBpbnRvIGBHcm91cGAgYW5kIGB5ZWFyc2AgY29sdW1ucy4KCmBgYHtyfQptYWpvcl9ncm91cHMgPC1tYWpvcl9ncm91cHMgJT4lCiAgdGlkeXI6OnNlcGFyYXRlKGNvbCA9IHZhbHVlLCBpbnRvID0gYygiR3JvdXAiLCAiWWVhcnMiKSwgc2VwID0gIig/PD1bOmFscGhhOl0pXFxzKD89WzAtOV0pIikKCm1ham9yX2dyb3VwcwpgYGAKCkxvb2tzIGdvb2QhCgpMZXQncyBhbHNvIGdldCByaWQgb2YgdGhlIGFsbCBjYXBzIGZvciB0aGUgbWFqb3IgY2F0ZWdvcmllcyBvZiB0aGUgYEdyb3VwYCBjb2x1bW4uIFdlIGNhbiBjb252ZXJ0IHRoZSB3b3JkcyB0byBvbmx5IGNhcGl0YWxpemUgdGhlIGZpcnN0IGxldHRlciB1c2luZyB0aGUgYHN0cl90b190aXRsZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuIFRvIHNwZWNpZmljYWxseSBtb2RpZnkgdGhlIGBHcm91cGAgY29sdW1uIHdlIGNhbiB1c2UgdGhlIGBtdXRhdGVgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIAoKV2UgYXJlIGFsc28gZ29pbmcgdG8gdXNlIGEgc3BlY2lhbCBwaXBlIG9wZXJhdG9yIGZyb20gdGhlIFtgbWFncml0dHJgIHBhY2thZ2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdyaXR0ci92aWduZXR0ZXMvbWFncml0dHIuaHRtbCkgY2FsbGVkIHRoZSBjb21wb3VuZCBhc3NpZ25tZW50IHBpcGUtb3BlcmF0b3Igb3Igc29tZXRpbWVzIHRoZSBkb3VibGUgcGlwZSBvcGVyYXRvci4gCgpUaGlzIGFsbG93cyB1cyB0byB1c2UgdGhlIGBtYWpvcl9ncm91cHNgIGFzIG91ciBpbnB1dCBhbmQgcmVhc3NpZ24gaXQgYXQgdGhlIGVuZCBhZnRlciBhbGwgdGhlIHN1YnNlcXVlbnQgc3RlcHMgaGF2ZSBiZWVuIHBlcmZvcm1lZCwgYWx0aG91Z2ggaW4gdGhpcyBjYXNlIGl0IGlzIG9ubHkgb25lIHN0ZXAuCgpgYGB7cn0KbWFqb3JfZ3JvdXBzICU8PiUKICBtdXRhdGUoR3JvdXAgPSBzdHJpbmdyOjpzdHJfdG9fdGl0bGUoR3JvdXApKQoKbWFqb3JfZ3JvdXBzCmBgYAoKTmljZSEgVGhhdCBsb29rcyBiZXR0ZXIuCgpGb3IgdGhlIHllYXIgZGF0YSB3ZSB3b3VsZCBsaWtlIHRvIHRyeSBzcGxpdHRpbmcgdGhlIHN0cmluZ3MgZm9yIGVhY2ggcm93IGludG8gZGlmZmVyZW50IGNvbHVtbnMgYmFzZWQgb24gYSBzcGFjZS4gQ3VycmVudGx5IGFsbCB0aGUgZGF0YSBpcyBsaXN0ZWQgaW4gb25lIGNvbHVtbiBjYWxsZWQgYFllYXJzYC4KCldlIGNhbiB1c2UgdGhlIGBzZXBhcmF0ZWAgZnVuY3Rpb24gb2YgdGhlIGB0aWR5cmAgcGFjYWtnZSBhZ2FpbiB0byBkbyB0aGlzLiBUaGlzIHdpbGwgYWxsb3cgdXMgdG8gc3BsaXQgdGhlIHJvd3MgYnkgc3BhY2VzLCBhcyB3ZWxsIGFzIHByb3ZpZGUgbmFtZXMgZm9yIHRoZSBuZXcgY29sdW1ucy4gCgoKYGBge3J9CgptYWpvcl9ncm91cHMgJTw+JQp0aWR5cjo6c2VwYXJhdGUoY29sID0gWWVhcnMsIAogICAgICAgICAgICAgICBpbnRvID0gYygiMjAwOCIsICIyMDEwIiwKICAgICAgICAgICAgICAgICAgICAgICAiMjAxMiIsICIyMDE0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIjIwMTYiLCAiMjAxNyIpLCAKICAgICAgICAgICAgICAgIHNlcCA9ICIgIikKCm1ham9yX2dyb3VwcwogCmBgYAoKCgpMb29rcyBwcmV0dHkgZ29vZCEKCldlIGFwcGVhciB0byBoYXZlIGFuIGVtcHR5IHJvdyBhdCB0aGUgdmVyeSBlbmQuIFNpbmNlIGFsbCB0aGUgdmFsdWVzIGFyZSBgTkFgLCB3ZSBjYW4gdXNlIHRoZSBgZHJvcF9uYSgpYCBmdW5jdGlvbiAgb2YgdGhlIGB0aWR5cmAgcGFja2FnZSB0byByZW1vdmUgaXQuCgpgYGB7cn0KbWFqb3JfZ3JvdXBzICU8PiUKICB0aWR5cjo6ZHJvcF9uYSgpCgptYWpvcl9ncm91cHMKYGBgCgpHcmVhdCwgbm93IHdlIGhhdmUgMTggcm93cy4KCkl0J3MgaW1wb3J0YW50IHRvIGxvb2sgdmVyeSBjYXJlZnVsbHkgYXQgdGhlIHRleHQuIEFnYWluLCB0aGVyZSBhcmUgc29tZSB2YWx1ZXMgbWlzc2luZyBhIGRlY2ltYWwgcGxhY2UuIEZvciBleGFtcGxlIHRoZSByb3cgd2hlcmUgdGhlIGBHcm91cGAgdmxhdWUgaXMgYEFzaWFuYCwgdGhlIHRoaXJkIGFuZCBmb3VydGggdmFsdWVzIGFyZSBtaXNzaW5nIGEgZGVjaW1hbCBwbGFjZS4KCkxvb2tpbmcgYXQgdGhlIG9yZ2luYWwgdGFibGUgd2Ugc2VlIHRoYXQgZXZlbiB2YWx1ZXMgbGlrZSAxMCBhcmUgcmVwcmVzZW50ZWQgYXMgMTAuMC4gCgpTbywgdG8gZml4IHRoaXMgd2Ugd2lsbCByZW1vdmUgYWxsIGRlY2ltYWxzICh3aGljaCBpcyBzb3J0IG9mIGxpa2UgbXVsdGlwbHlpbmcgYWxsIHZhbHVlcyB0aGF0IGRvIGhhdmUgYSBkZWNpbWFsIGJ5IDEwKSBhbmQgdGhlbiB3ZSB3aWxsIG11bHRpcGx5IGFsbCB2YWx1ZXMgYnkgLjAxIHRvIGFkZCB0aGUgZGVjaW1hbHMgYmFjay4gV2Ugd2lsbCB1c2UgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24gY29tYmluZWQgd2l0aCB0aGUgYGFjcm9zcygpYCBmdW5jdGlvbiB3aGljaCBhbGxvd3MgdXMgdG8gc3BlY2lmeSB3aGljaCBjb2x1bW5zIHdlIHdhbnQgdG8gcGVyZm9ybSBhIGZ1bmN0aW9uIG9uLiBXZSB3YW50IHRvIGRvIHRoaXMgdG8gYWxsIHRoZSB5ZWFyIGNvbHVtbnMsIHNvIHdlIGNhbiBleGNsdWRlIHRoZSBgR3JvdXBgIGNvbHVtbiBieSB1c2luZyBhIG1pbnVzIHNpZ24gYC1gIGluIHRoZSBgLmNvbHNgIGFyZ3VtZW50IG9mIHRoZSBgYWNyb3NzKClgIGZ1bmN0aW9uIGxpa2Ugc286IGBtdXRhdGUoYWNyb3NzKC5jb2xzID0gLUdyb3VwKSlgCgoKRmluYWxseSwgd2Ugd2lsbCB1c2UgdGhlIGBzdHJfcmVtb3ZlKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RyaW5ncmAgcGFja2FnZSB0byBmaW5kIGluc3RhbmNlcyBvZiAiLiIgYW5kIHJlbW92ZSB0aGVtLiBTaW5jZSAiLiIgaXMgYSByZWdleCwgYW5kIGluZGljYXRlcyBhbnkgY2hhcmFjdGVyIHN0cmluZywgdGh1cyB3ZSBuZWVkICJcXCIgdG8gaGF2ZSBSIGludGVycHJldCBhIGRlY2ltYWwgb3IgYSBwZXJpb2QgaW5zdGVhZCwgYXMgd2UgY2FuIHNlZSBmcm9tIHRoZSBSU3R1ZGlvIGNoZWV0c2hlYXQ6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjYwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJyZWdleF9wZXJpb2QucG5nIikpCgpgYGAKClRvIHBhc3MgdGhlIGRhdGEgZnJvbSBhbGwgdGhlIGNvdWx1bW5zIGV4Y2VwdCBvdXIgYEdyb3VwYCB2YXJpYWJsZSBpbnRvIG91ciBgc3RyX3JlbW92ZSgpYCBmdW5jdGlvbiwgd2UgbmVlZCB0byB1c2UgdGhlIGAuYCBub3RhdGlvbiBhcyBhIHJlcGxhY2VtZW50IGZvciB0aGUgZGF0YSB0aGF0IHdlIHNwZWNpZmllZCBieSB0aGUgYC5jb2xzYGFyZ3VtZW50IGFuZCB3ZSBuZWVkIHRvIHVzZSBgfmAgaW4gZnJvbnQgb2YgdGhlIGZ1bmN0aW9uIG5hbWUuIAoKYGBge3J9CgogbWFqb3JfZ3JvdXBzICU8PiUKICAgIG11dGF0ZShhY3Jvc3MoLmNvbHMgPSAtR3JvdXAsIH5zdHJfcmVtb3ZlKHN0cmluZyA9IC4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiXFwuIikpKQoKbWFqb3JfZ3JvdXBzCmBgYAoKCkdyZWF0LCBub3cgaW4gb3JkZXIgdG8gbXVsdGlwbHkgZWFjaCB2YWx1ZSBieSAwLjEgd2UgbmVlZCB0byBmaXJzdCBtYWtlIHRoZSB2YWx1ZXMgbnVtZXJpYy4gQ3VycmVudGx5IHdlIGNhbiB0ZWxsIHRoYXQgdGhleSBhcmUgY2hhcmFjdGVyIHN0cmluZ3MgYmFzZWQgb24gdGhlIGA8Y2hhcj5gIHZhbHVlcyBsaXN0ZWQgdW5kZXIgZWFjaCBjb2x1bW4gbmFtZS4KCgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgZm9yIGFuIGV4cGxhbmF0aW9uIGFib3V0IGRhdGEgdHlwZXMgaW4gUiBhbmQgYWJvdXQgY2hhcmFjdGVyIHN0cmluZ3MuIDwvc3VtbWFyeT4KClRoZXJlIGFyZSBzZXZlcmFsIGNsYXNzZXMgb2YgZGF0YSBpbiBSIHByb2dyYW1taW5nLiAKQ2hhcmFjdGVyIGlzIG9uZSBvZiB0aGVzZSBjbGFzc2VzLiAKQSBjaGFyYWN0ZXIgc3RyaW5nIGlzIGFuIGluZGl2aWR1YWwgZGF0YSB2YWx1ZSBtYWRlIHVwIG9mIGNoYXJhY3RlcnMuIApUaGlzIGNhbiBiZSBhIHBhcmFncmFwaCwgbGlrZSB0aGUgbGVnZW5kIGZvciB0aGUgdGFibGUsIG9yIGl0IGNhbiBiZSBhIHNpbmdsZSBsZXR0ZXIgb3IgbnVtYmVyIGxpa2UgdGhlIGxldHRlciBgImEiYCBvciB0aGUgbnVtYmVyIGAiMyJgLiAKSWYgZGF0YSBhcmUgb2YgY2xhc3MgY2hhcmFjdGVyLCB0aGFuIHRoZSBudW1lcmljIHZhbHVlcyB3aWxsIG5vdCBiZSBwcm9jZXNzZWQgbGlrZSBhIG51bWVyaWMgdmFsdWUgaW4gYSBtYXRoZW1hdGljYWwgc2Vuc2UuIApJZiB5b3Ugd2FudCB5b3VyIG51bWVyaWMgdmFsdWVzIHRvIGJlIGludGVycHJldGVkIHRoYXQgd2F5LCB0aGV5IG5lZWQgdG8gYmUgY29udmVydGVkIHRvIGEgbnVtZXJpYyBjbGFzcy4gClRoZSBvcHRpb25zIHR5cGljYWxseSB1c2VkIGFyZSBpbnRlZ2VyICh3aGljaCBoYXMgbm8gZGVjaW1hbCBwbGFjZSkgYW5kIGRvdWJsZSBwcmVjaXNpb24gKHdoaWNoIGhhcyBhIGRlY2ltYWwgcGxhY2UpLiAKCjwvZGV0YWlscz4KCgpUbyBjb252ZXJ0IG91ciB2YWx1ZXMgdG8gYmUgbnVtZXJpYyB3ZSBjYW4gdXNlIHRoZSBiYXNlIGBhcy5udW1lcmljKClgIGZ1bmN0aW9uLiBBZ2FpbiB3ZSB3aWxsIHVzZSBgbXV0YXRlKClgIGFuZCBgYWNyb3NzKClgLiBTaW5jZSB0aGlzIGZ1bmN0aW9uIGRvZXNuJ3QgcmVxdWlyZSBhbnkgYXJndW1lbnRzLCB3ZSBkb24ndCBuZWVkIHRvIHNwZWNpZnkgaXQncyBpbnB1dCBsaWtlIHdlIGp1c3QgZGlkIGZvciB0aGUgYHN0cl9yZW1vdmUoKWAgYnV0IHdlIGNvdWxkIGRvIHNvIGFzIHNob3duIGJlbG93LgoKYGBge3J9Cm1ham9yX2dyb3VwcyAlPD4lCiAgIG11dGF0ZShhY3Jvc3MoLmNvbHMgPSAtR3JvdXAsIGFzLm51bWVyaWMpKQoKI3RoaXMgaXMgZXF1aXZhbGVudDoKCiNtYWpvcl9ncm91cHMgJTw+JQojICAgbXV0YXRlKGFjcm9zcyguY29scyA9IC1Hcm91cCwgfmFzLm51bWVyaWMoLikpKQoKbWFqb3JfZ3JvdXBzCmBgYAoKR3JlYXQsIHdlIGNhbiBzZWUgdGhhdCB0aGUgeWVhciB2YXJpYWJsZXMgYXJlIG5vdyBudW1lcmljIGFzIHRoZXkgYXJlIG5vdyB0eXBlIGRvdWJsZSBhcyBpbmRpY2F0ZWQgYnkgdGhlIGA8ZGJsPmAgYmVsb3cgZWFjaCBjb2x1bW4gbmFtZS4gU2VlIHRoZSBhYm92ZSBzZWN0aW9uIGFib3V0IGRhdGEgdHlwZXMgaWYgeW91IGFyZSB1bmZhbWlsaWFyIHdpdGggdHlwZSBkb3VibGUuCgpPSywgbm93IHdlIGNhbiBtdWx0aXBseSBlYWNoIHZhbHVlIGJ5IDAuMSB0byBhZGQgb3VyIGRlY2ltYWwgcG9pbnRzIGJhY2sgYW5kIGdldCBiYWNrIHRvIHRoZSBvcmdpbmFsIHZhbHVlcy4KCmBgYHtyfQoKbWFqb3JfZ3JvdXBzICU8PiUKICAgIG11dGF0ZShhY3Jvc3MoLmNvbHMgPSAtR3JvdXAsIH4gLiAqIDAuMSkpCgptYWpvcl9ncm91cHMKCmBgYAoKTm93IGlzIGEgZ29vZCB0aW1lIHRvIGRvdWJsZSBjaGVjayB0aGF0IG91ciB0YWJsZSBsb29rcyBsaWtlIHdoYXQgd2UgZXhwZWN0LgoKCmBgYHtyLCBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJnZW5kZXJfcmFjZV9ldGhuaWNpdHkucG5nIikpCmBgYAoKTG9va3MgZ29vZCEKCldlIGFsc28gd2FudCB0byBhZGQgYSBjb3VwbGUgb2YgdmFyaWFibGVzIGFib3V0IGBSYWNlX0V0aG5pY2l0eWAgYW5kIGBHZW5kZXJgIHNvIHRoYXQgd2UgY2FuIHNlbGVjdCBhY3Jvc3MgZ3JvdXBzIGxhdGVyLiAgV2UgY2FuIHVzZSB0aGUgYHJlY29kZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGNoYW5nZSBzcGVjaWZpYyB2YWx1ZXMsIGFzIHdlIGNyZWF0ZSBhIG5ldyBgUmFjZV9FdGhuaWNpdHlgIHZhcmlhYmxlIGZyb20gdGhlIGBHcm91cGAgdmFyaWFibGUuIEZvciB0aGUgRGF0YSBmb3IgYWxsIG9mIHRoZSBVUyB3ZSB3YW50IHRoZSBgUmFjZV9FdGhuaWNpdHlgIHZhcmlhYmxlIHZhbHVlcyB0byBiZSBgIkFsbF9yYWNlcyJgLgoKYGBge3J9Cm1ham9yX2dyb3VwcyAlPD4lIAogIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9IAogICAgICAgICAgIHJlY29kZShHcm91cCwgIlVuaXRlZCBTdGF0ZXMiID0gIkFsbF9yYWNlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZlbWFsZSIgPSAiQWxsX3JhY2VzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYWxlIiA9ICJBbGxfcmFjZXMiKSkKCmhlYWQobWFqb3JfZ3JvdXBzKQpgYGAKCgpXZSBhbHNvIHdhbnQgdG8gcmVtb3ZlIE1hbGUgYW5kIEZlbWFsZSBmcm9tIHRoaXMgIlJhY2VfRXRobmljaXR5IiB2YXJpYWJsZSwgV2UgY2FuIGRvIHNvIHVzaW5nIHRoZSBgc3RyX3JlbW92ZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuIEltcG9ydGFudGx5LCB3ZSBhcmUgYWxzbyByZW1vdmluZyB0aGUgc3BhY2UgYmVvcmUgIkZlbWFsZSIgYW5kICJNYWxlLgoKYGBge3J9Cm1ham9yX2dyb3VwcyAlPD4lIAogIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9IHN0cl9yZW1vdmUoc3RyaW5nID0gUmFjZV9FdGhuaWNpdHksICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIgRmVtYWxlfCBNYWxlIikpCgpoZWFkKG1ham9yX2dyb3VwcykKYGBgCgpGb3IgdGhlIG5ldyBgR2VuZGVyYCB2YXJpYWJsZSB3ZSB3b3VsZCBsaWtlIHRvIGV4dHJhY3QganVzdCB0aGUgIkZlbWFsZSIgYW5kICJNYWxlIiB0ZXh0IGZyb20gdGhlIGBHcm91cGAgdmFyaWFibGUuIFRoZSBgc3RyX2V4dHJhY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlIHdpbGwgZG8gdGhpcywgYW5kIGl0IHdpbGwgZ2l2ZSB1cyBhbiBgTkFgIHZhbHVlIGZvciBhbnkgcm93cyB3aGhlcmUgIkZlbWFsZSIgb3IgIk1hbGUiIHdlcmUgbm90IHByZXNlbnQuIFdlIGNhbiB0aGVuIHJlcGxhY2UgdGhlIGBOQWAgdmFsdWVzIHdpdGggIHRoZSB0ZXh0ICJBbGwiIHRvIHJlcHJlc2VudCB0aGUgdG90YWwgdmFsdWUgZm9yIGJvdGggbWFsZSBhbmQgZmVtYWxlIHVzaW5nIHRoZSBgcmVwbGFjZV9uYSgpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyKClgIHBhY2thZ2UuCgpgYGB7cn0KCm1ham9yX2dyb3VwcyAlPD4lIAogIG11dGF0ZShHZW5kZXIgPSBzdHJfZXh0cmFjdChzdHJpbmcgPSBHcm91cCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJGZW1hbGV8TWFsZSIpKSAlPiUKICBtdXRhdGUoR2VuZGVyID0gcmVwbGFjZV9uYShHZW5kZXIsIHJlcGxhY2UgPSAiQWxsIikpCgpoZWFkKG1ham9yX2dyb3VwcykKYGBgCgpXZSB3b3VsZCBhbHNvIGxpa2UgdG8gcmVwbGFjZSBMYXRpbm8gYW5kIExhdGluYSB3aXRoIExhdGlueC4gCldlIGNhbiAgdXNlIGFub3RoZXIgYHN0cmluZ19yYCBmdW5jdGlvbiBmb3IgdGhpcy4gVGhpcyBmdW5jdGlvbiwgYHN0cl9yZXBsYWNlKClgIGFsbG93cyB1cyB0byByZW1vdmUgYW5kIHJlcGxhY2UgYSBwYXJ0aWN1bGFyIHBhdHRlcm4uIAoKYGBge3J9Cm1ham9yX2dyb3VwcyAlPD4lCiAgbXV0YXRlKGFjcm9zcyguY29scyA9IGMoR3JvdXAsIFJhY2VfRXRobmljaXR5KSwgCiAgICAgICAgICAgICAgICB+c3RyX3JlcGxhY2Uoc3RyaW5nID0gLiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIkxhdGlub3xMYXRpbmEiLAogICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJMYXRpbngiKSkpCmBgYAoKIyMjIyB7LnRoaW5rX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KCldoeSBpcyB0aGUgYHN0cl9yZXBsYWNlKClgIGZ1bmN0aW9uIGluIHRoaXMgY2FzZSBhIGJldHRlciBvcHRpb24gdGhhbiB1c2luZyB0aGUgYHJlY29kZSgpYCBmdW5jdGlvbj8KCiMjIyMKCmBgYHtyfQptYWpvcl9ncm91cHMKYGBgCkZpbmFsbHksIHdlIHdvdWxkIGxpa2UgdG8gY2hhbmdlIHRoZSBzaGFwZSBvZiBvdXIgdGFibGUgc28gdGhhdCB3ZSBoYXZlIGEgbmV3IGNvbHVtbiB0aGF0IHJlcHJlc2VudHMgdGhlIHllYXIgYW5kIGEgbmV3IGNvbHVtbiB0aGF0IHJlcHJlc2VudHMgdGhlIHZhbHVlIGZvciB0aGF0IHllYXIuCgpUbyBkbyBzbyB3ZSB3aWxsIGJlIG1ha2luZyBvdXIgdGFibGUgImxvbmdlciIsIG1lYW5pbmcgdGhhdCBpdCB3aWxsIGhhdmUgZmV3ZXIgY29sdW1ucyBhbmQgbW9yZSByb3dzLiAKU2VlIFtoZXJlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XaWRlX2FuZF9uYXJyb3dfZGF0YSkgZm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgZGlmZmVyZW50IHRhYmxlIGZvcm1hdHMsIHR5cGljYWxseSByZWZlcnJlZCB0byBhcyB3aWRlIGFuZCBsb25nIG9yIHNvbWV0aW1lcyBuYXJyb3cuCgpXZSB3aWxsIHVzZSB0aGUgYHBpdm90X2xvbmdlcigpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlIHRvIGNoYW5nZSB0aGUgc2hhcGUgb2Ygb3VyIHRhYmxlLiAKClRoZXJlIGFyZSAzIG1haW4gYXJndW1lbnRzIGluIHRoaXMgZnVuY3Rpb246ICAgCgoxLiBgY29sc2AgLSB3aGljaCBzcGVjaWZpZXMgd2hhdCBjb2x1bW5zIHRvIGNvbGxhcHNlICAKMi4gYG5hbWVzX3RvYCAtIHdoaWNoIHNwZWNpZmllcyB0aGUgbmFtZSBvZiB0aGUgbmV3IGNvbHVtbiB0aGF0IHdpbGwgYmUgY3JlYXRlZCB0aGF0IHdpbGwgY29udGFpbiB0aGUgY29sdW1uIG5hbWVzIG9mIHRoZSBjb2x1bW5zIHlvdSBhcmUgY29sbGFwc2luZyAgCjMuIGB2YWx1ZXNfdG9gIC0gd2hpY2ggc3BlY2lmaWVzIHRoZSBuYW1lIG9mIHRoZSBuZXcgY29sdW1uIHRoYXQgd2lsbCBiZSBjcmVhdGVkIHRoYXQgd2lsbCBjb250YWluIHRoZSB2YWx1ZXMgZnJvbSB0aGUgY29sdW1ucyB5b3UgYXJlIGNvbGxhcHNpbmcgCgpUbyBzcGVjaWZ5IHRoYXQgd2Ugd2FudCB0byBjb2xsYXBzZSBhbGwgdGhlIGNvbHVtbnMgdGhhdCBoYXZlIHllYXIgdmFsdWVzLCB3ZSBjYW4gY2hvc2UgdGhvc2UgdGhhdCBjb250YWluIHRoZSBzdHJpbmcgYCIyMCJgIHVzaW5nIHRoZSBgY29udGFpbnMoKWAgZnVuY3Rpb24gb2YgYGRwbHlyYC4gCgpgYGB7cn0KbWFqb3JfZ3JvdXBzX2xvbmcgPC0gbWFqb3JfZ3JvdXBzICU+JQogIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scyA9IGNvbnRhaW5zKCIyMCIpLAogICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwKICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiUGVyY2VudCIsCiAgICAgICAgICAgICAgbmFtZXNfcHJlZml4ID0gIlBlcmNfIikgJT4lCiAgZHBseXI6Om11dGF0ZShZZWFyID0gYXMubnVtZXJpYyhZZWFyKSkKCm1ham9yX2dyb3Vwc19sb25nCmBgYAoKCkV4Y2VsbGVudCwgbm93IHdlIG5lZWQgdG8gZG8gdGhlIHNhbWUgZm9yIHRoZSBvdGhlciB0d28gdGFibGVzIG9uIHRoaXMgcGFnZToKCmBgYHtyLCBlY2hvICA9IEZBTFNFfQoKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImdlbmRlcl9yYWNlX2V0aG5pY2l0eV9vdmVydmlldy5wbmciKSkKYGBgCgoKIyMjIEFzaWFuIFN1Ymdyb3VwcyAyMDE3CgpOb3cgbGV0J3MgZG8gdGhlIHNhbWUgZm9yIHRoZSBBc2lhbiBzdWJncm91cHMgdGFibGUuCgpGaXJzdCB3ZSB3aWxsIHN0YXJ0IGJ5IGltcG9ydGluZyBhIHNjcmVlbnNob3QgZm9yIHRoaXMgdGFibGUgd2l0aG91dCB0aGUgaGVhZGVyLCBhcyB3ZSBkaWQgYmVmb3JlLiBUaGUgbmFtZSBvZiB0aGUgZmlsZSBmb3IgdGhlIHNjcmVlbnNob3QgaXMgYGFzaWFuX3N1Ymdyb3Vwcy5wbmdgIGFuZCBpdCBpcyBsb2NhdGVkIGluIHRoZSBgaW1nYCBkaXJlY3RvcnkuCgojIyMjIHsucmVjYWxsX2NvZGVfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKQ2FuIHlvdSByZWNhbGwgdGhlIGNvbW1hbmQgdG8gaW1wb3J0IGFuIGltYWdlIGludG8gUiB1c2luZyB0aGUgYG1hZ2lja2AgcGFja2FnZT8KCiMjIyMKCgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+CgoKYGBge3IsIG91dC53aWR0aH0KYXNpYW5fc3ViZ3JvdXBzIDwtIGltYWdlX3JlYWQoaGVyZTo6aGVyZSgiaW1nIiwgImFzaWFuX3N1Ymdyb3Vwc18yMDE3LnBuZyIpKQpgYGAKCjwvZGV0YWlscz4KCgpgYGB7ciwgb3V0LndpZHRoPSI0MCUifQphc2lhbl9zdWJncm91cHMKYGBgCgojIyMjIHsucmVjYWxsX2NvZGVfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKQ2FuIHlvdSByZWNhbGwgdGhlIGNvbW1hbmQgdG8gZXh0cmFjdCB0aGUgdGV4dCBmcm9tIGFuIGltYWdlIHVzaW5nIHRoZSBgbWFnaWNrYCBwYWNrYWdlPyAKCiMjIyMKCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4KCmBgYHtyfQphc2lhbl9zdWJncm91cHMgPC0gaW1hZ2Vfb2NyKGFzaWFuX3N1Ymdyb3VwcykKYGBgCgo8L2RldGFpbHM+CgpgYGB7cn0KYXNpYW5fc3ViZ3JvdXBzCmBgYAoKCk5vdyB3ZSBhZ2FpbiB3YW50IHRvIHNwbGl0IHRoZSBkYXRhIGludG8gcm93cyBiYXNlZCBvbiB0aGUgbmV3bGluZSByZWdleC4gVGhpcyBpcyBzb21ldGhpbmcgd2Ugd2lsbCBjb250aW51ZSB0byBkbyBmb3IgYWxsIHRoZSB0YWJsZXMuCgpPbmUgb3B0aW9uIGlzIHRvIGNvcHkgYW5kIHBhc3RlIGNvZGUgd2Ugd3JvdGUgYWJvdmUgZWFjaCB0aW1lLiAKSG93ZXZlciwgdGhpcyBpcyBub3QgdmVyeSBlZmZpY2llbnQgYW5kIGlzIGVycm9yIHByb25lLgpBbHRlcm5hdGl2ZWx5LCB3ZSBjYW4gY3JlYXRlIGEgUiBmdW5jdGlvbiB0byBhY2NvbXBsaXNoIHRoaXMgc3VjY2luY3RseS4gCkZ1bmN0aW9ucyBhbGxvdyB1cyB0byBwZXJmb3JtIHRoZSBzYW1lIHByb2Nlc3Mgb24gbXVsdGlwbGUgZGF0YSBpbnB1dHMuIApTZWUgW3RoaXMgb3RoZXIgY2FzZSBzdHVkeV0oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL29jcy1ibG9vbWJlcmctdmFwaW5nLWNhc2Utc3R1ZHkvKSBmb3IgbW9yZSBkZXRhaWxzIGFib3V0IGhvdyB0byB3cml0ZSBhIGZ1bmN0aW9uLgoKSW4gZ2VuZXJhbCwgdGhlIHByb2Nlc3Mgb2Ygd3JpdGluZyBmdW5jdGlvbnMgaW52b2x2ZXMgZmlyc3Qgc3BlY2lmeWluZyBhbiBpbnB1dCB0aGF0IGlzIHVzZWQgd2l0aGluIHRoZSBmdW5jdGlvbiB0byBjcmVhdGUgYW4gb3V0cHV0LiBJbiB0aGlzIGNhc2UsIHRoZSBkYXRhIGlucHV0IGlzIGB0ZXh0YCAgd2hpY2ggd2lsbCBiZSByZXBsYWNlZCBieSB0aGUgYWN0dWFsIGltYWdlIHRleHQgdGhhdCB3ZSBhcmUgd29ya2luZyBvbiwgYW5kIHRoZW4gdXNlZCBpbiB0aGUgc3Vic2VxdWVudCBzdGVwcyB0byB3cmFuZ2xlIHRoZSBkYXRhLiBXZSB3aWxsIGNhbGwgb3VyIGZ1bmN0aW9uIGBtYWtlX3Jvd3MoKWAuCgpgYGB7cn0KCm1ha2Vfcm93cyA8LSBmdW5jdGlvbih0ZXh0KXsKICB0ZXh0ICU+JQogIHN0cl9zcGxpdCgiXG4iKSAlPiUKICB1bmxpc3QoKSAlPiUKICBhc190aWJibGUoKQp9CgpgYGAKCgpHcmVhdCEgTm93IGxldCdzIGFwcGx5IG91ciBmdW5jdGlvbiB0byB0aGUgYGFzaWFuX3N1Ymdyb3Vwc2AgZGF0YSEKCmBgYHtyfQphc2lhbl9zdWJncm91cHMgPC0gbWFrZV9yb3dzKGFzaWFuX3N1Ymdyb3VwcykgCgphc2lhbl9zdWJncm91cHMKYGBgCgoKQXMgeW91IGNhbiBzZWUsIHRoZXJlIGFyZSBzb21lIHN0cmFuZ2UgdmFsdWVzIGZvciBzb21lIG9mIHRoZSByb3dzLiBGb3IgZXhhbXBsZSB0aGUgcm93IHRoYXQgc3RhcnRzIHdpdGggYENISU5FU0UgTUFsZWAgaGFzIGBBVGAgcGVyY2VudGFnZSBvZiBkaXNjb25uZWN0ZWQgeW91dGgsIGFuZCB0aGUgcm93IHRoYXQgc2hvdWxkIHNheSBgRklMSVBJTk9gIHNheXMgYFPihKJT4oSiflNTYC4KCgoKYGBge3IsIGVjaG8gPSBGQUxTRX0KCnRlbXAgPC1hc2lhbl9zdWJncm91cHMgJT4lCiAgcHVsbCh2YWx1ZSkgJT4lCiAgc3RyX3NwbGl0KCIgIikKdGVtcFs4XQp0ZW1wWzI4XQpgYGAKClRoZSByb3dzIHdpdGggbm8gdmFsdWVzIGFyZSBwb3NzaWJseSBjYXVzaW5nIHRoaXMgaXNzdWUuICBBY2NvcmRpbmcgdG8gdGhlIFBERiwgdGhlc2Ugc3BhY2VzIGFyZSBlbXB0eSB0byBkZW5vdGUgdGhhdCB0aGUgZXN0aW1hdGVzIHdlcmUgdW5yZWxpYWJsZSBmb3IgdGhlc2UgZ3JvdXBzLgoKU28gd2Ugd2lsbCBub3cgaW1wb3J0IGFuZCBleHRyYWN0IHRleHQgZnJvbSB0aHJlZSBzY3JlZW5zaG90cyBvZiB0aGlzIHRhYmxlIHdoZXJlIHdlIHN0b3AganVzdCBhZnRlciB0aGUgcm93IHRoYXQgc3RhcnRzIHdpdGggYFBBS0lTVEFOSWAgaW4gdGhlIGZpcnN0IGltYWdlLCBhbmQgdGhlbiBhbiBpbWFnZSBvZiB0aGUgS29yZWFuIHJvd3MgdXAgdG8gdGhlIG5leHQgcm93IHdpdGggbm8gdmFsdWVzLCBhbmQgZmluYWxseSBhbiBpbWFnZSBzdGFydGluZyBhdCB0aGUgcm93IHRoYXQgc3RhcnRzIHdpdGggYEZJTElQTk9gLgoKYGBge3J9CkFzaWFuX3N1Yl9BIDwtIGltYWdlX3JlYWQoaGVyZSgiaW1nIiwgImFzaWFuX3N1Yl9BLnBuZyIpKQpBc2lhbl9zdWJfQiA8LSBpbWFnZV9yZWFkKGhlcmUoImltZyIsICJhc2lhbl9zdWJfQi5wbmciKSkKQXNpYW5fc3ViX0MgPC0gaW1hZ2VfcmVhZChoZXJlKCJpbWciLCAiYXNpYW5fc3ViX0MucG5nIikpCgpBc2lhbl9zdWJfQQpBc2lhbl9zdWJfQgpBc2lhbl9zdWJfQyAKCmBgYAoKCmBgYHtyfQpBc2lhbl9zdWJfQSA8LSBpbWFnZV9vY3IoQXNpYW5fc3ViX0EpCkFzaWFuX3N1Yl9CIDwtIGltYWdlX29jcihBc2lhbl9zdWJfQikKQXNpYW5fc3ViX0MgPC0gaW1hZ2Vfb2NyKEFzaWFuX3N1Yl9DKQoKQXNpYW5fc3ViX0EgPC0gbWFrZV9yb3dzKEFzaWFuX3N1Yl9BKQpBc2lhbl9zdWJfQiA8LSBtYWtlX3Jvd3MoQXNpYW5fc3ViX0IpCkFzaWFuX3N1Yl9DIDwtIG1ha2Vfcm93cyhBc2lhbl9zdWJfQykKCkFzaWFuX3N1Yl9BIApBc2lhbl9zdWJfQgpBc2lhbl9zdWJfQyAKYGBgCgpNdWNoIGJldHRlciEKCldlIGNhbiBub3cgY29tYmluZSB0aGUgb2JqZWN0cyB3aXRoIHRoZSBgYmluZF9yb3dzKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UsIHdoaWNoIHdpbGwgYXBwZW5kIGVhY2ggb2YgdGhlc2UgdGliYmxlcyB0b2dldGhlciBvbmUgYWZ0ZXIgdGhlIG90aGVyLgoKYGBge3J9CmFzaWFuX3N1Yl8yMDE3IDwtYmluZF9yb3dzKEFzaWFuX3N1Yl9BLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgQXNpYW5fc3ViX0IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEFzaWFuX3N1Yl9DKQoKYXNpYW5fc3ViXzIwMTcKYGBgCgpMb29rcyBwcmV0dHkgZ29vZCEgCgpOb3cgd2UgaGF2ZSBzaW1pbGFyIHdyYW5nbGluZyBzdGVwcyB0byBwZXJmb3JtIGFzIHdlIGRpZCBwcmV2aW91c2x5IGFuZCB3ZSB3aWxsIG5lZWQgdG8gZG8gdGhlIHNhbWUgZm9yIHRoZSBMYXRpbnggc3ViZ3JvdXBzIHRhYmxlLiBTbyBpdCBpcyBhIGdvb2QgaWRlYSB0byBtYWtlIGFub3RoZXIgZnVuY3Rpb24uCgpFdmVuIHRob3VnaCB3ZSBhcHBlYXIgdG8gaGF2ZSBhbGwgb2YgdGhlIGRlY2ltYWwgcGxhY2VzIGZvciB0aGUgdmFsdWVzLCB3ZSB3aWxsIGluY2x1ZGUgdGhpcyBpbiBvdXIgZnVuY3Rpb24sIGp1c3QgdG8gbWFrZSBzdXJlIHRoZSBkYXRhIGlzIGNvcnJlY3QuCgoKIyMjIyB7LmV4cGxhaW5fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKQ2FuIHlvdSBleHBsYWluIHdoYXQgZWFjaCBvZiB0aGUgY29tbWFuZHMgYXJlIGRvaW5nIHdpdGhpbiB0aGUgZnVuY3Rpb24/CgojIyMjCgpgYGB7cn0KCmNsZWFuX3RhYmxlIDwtIGZ1bmN0aW9uKHRhYmxlKXsKICB0YWJsZSAlPiUKICAgIHNlcGFyYXRlKC4sIGNvbCA9IHZhbHVlLAogICAgICAgICAgICAgICBpbnRvID0gYygiR3JvdXAiLCAiUGVyY2VudGFnZSIpLAogICAgICAgICAgICAgICAgc2VwID0gICIoPzw9WzphbHBoYTpdKVxccyg/PVswLTldKSIpICU+JSAKICAgIGRyb3BfbmEoKSAlPiUKICAgIG11dGF0ZShHcm91cCA9IHN0cl90b190aXRsZShHcm91cCkpICU+JQogICAgbXV0YXRlKFBlcmNlbnRhZ2UgPSBzdHJfcmVtb3ZlKHN0cmluZyA9IFBlcmNlbnRhZ2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIlxcLiIpKSAlPiUKICAgIHNlcGFyYXRlKFBlcmNlbnRhZ2UsIGMoIlBlcmNlbnQiKSwgc2VwID0gIiAiKSAlPiUKICAgIG11dGF0ZShQZXJjZW50ID0gYXMubnVtZXJpYyhQZXJjZW50KSkgJT4lCiAgICBtdXRhdGUoUGVyY2VudCA9IFBlcmNlbnQgKiAwLjEpICU+JQogICAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gcmVjb2RlKEdyb3VwLCAKICAgICAgICAgICAgICAgICAgICAgICAgIlVuaXRlZCBTdGF0ZXMiID0gIkFsbF9yYWNlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRmVtYWxlIiA9ICJBbGxfcmFjZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWFsZSIgPSAiQWxsX3JhY2VzIikpICU+JQogICAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gCiAgICAgICAgICAgICBzdHJfcmVtb3ZlKHN0cmluZyA9IFJhY2VfRXRobmljaXR5LCAgCiAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIgRmVtYWxlfCBNYWxlIikpJT4lCiAgICBtdXRhdGUoR2VuZGVyID0gCiAgICAgICAgICAgICBzdHJfZXh0cmFjdChzdHJpbmcgPSBHcm91cCwKICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9IkZlbWFsZXxNYWxlIikpICU+JQogICAgbXV0YXRlKEdlbmRlciA9IHJlcGxhY2VfbmEoR2VuZGVyLCByZXBsYWNlID0gIkFsbCIpKQogCn0KCmBgYAoKCgpgYGB7cn0KYXNpYW5fc3ViXzIwMTcgPC0gY2xlYW5fdGFibGUodGFibGUgPSBhc2lhbl9zdWJfMjAxNykKYXNpYW5fc3ViXzIwMTcKYGBgCgpHcmVhdCEgVGhpcyBsb29rcyBhcyB3ZSBleHBlY3RlZC4gCgojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKV2h5IGRvIHdlIG5vdCBuZWVkIHRvIHVzZSBgcGl2b3RfbG9uZ2VyKClgIHdpdGggdGhpcyBkYXRhPwoKIyMjIwoKCiMjIyBMYXRpbnggU3ViZ3JvdXBzIDIwMTcKCgpSZWNhbGwgdGhhdCB0aGlzIGlzIHRoZSB0YWJsZSB3ZSB3YW50IHRvIHdyYW5nbGU6CgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImxhdGlueDIwMTcucG5nIikpCmBgYAoKIyMjIyB7LnRoaW5rX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KCkRvIHlvdSBub3RpY2UgYW55dGhpbmcgaW5jb3JyZWN0IGFib3V0IHRoaXMgdGFibGU/CgojIyMjCgpTb21ldGltZXMgd2hlbiB3cmFuZ2xpbmcgdGV4dCBkYXRhLCB3ZSB3aWxsIGNvbWUgYWNyb3NzIGEgdHlwby4gV2UgbmVlZCB0byBkZXRlcm1pbmUgaG93IHRvIHJlc3BvbmQgdG8gdGhlIHR5cG8gYW5kIG1ha2Ugbm90ZSBvZiBpdC4gSXQncyBvZnRlbiBiZXN0IHRvIGNvbnN1bHQgYSBzZWNvbmRhcnkgc291cmNlIHRvIGNvbmZpcm0gdGhhdCBjaGFuZ2VzIG1hZGUgYXJlIGFjY3VyYXRlLiAKCkZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBjYXNlIHN0dWR5LCB3ZSB3aWxsIGFzc3VtZSB0aGF0IHRoZSBmaXJzdCBvZiB0aGUgdHdvIHJvd3MgcmVwcmVzZW50cyBtYWxlIGRpc2Nvbm5lY3Rpb24gcmF0ZXMgaW4gdGhlIExhdGluby9hIHN1Ymdyb3VwOyB0aGlzIHdvdWxkIGJlIGNvbnNpc3RlbnQgd2l0aCB0aGUgb3JkZXJpbmcgb2YgZ2VuZGVycyBpbiB0aGUgcHJldmlvdXMgc3ViZ3JvdXBzLiAKCldlIHdpbGwgbWFrZSBzdXJlIHRvIGNvcnJlY3QgdGhpcyB0eXBvIHdoZW4gd2UgY2FuLiAKCgpBZnRlciB0cmlhbCBhbmQgZXJyb3IsIHR3byBzY3JlZW5zaG90cyB3ZXJlIGRldGVybWluZWQgYmVzdCBmb3IgaW1wb3J0aW5nIHRoaXMgZGF0YS4gVGhlIG5hbWVzIG9mIHRoZSBmaWxlcyBmb3IgdGhlIHNjcmVlbnNob3RzIGFyZSBgbGF0aW54X3N1Yl9BLnBuZ2AgYW5kIGAibGF0aW54X3N1Yl9CLnBuZ2AuIFRoZXkgYXJlIGxvY2F0ZWQgaW4gdGhlIGBpbWdgIGRpcmVjdG9yeS4KCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpDYW4geW91IHJlY2FsbCB0aGUgY29tbWFuZHMgdG8gaW1wb3J0IGFuZCBleHRyYWN0IHRoZSBkYXRhPwoKIyMjIwoKCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4KCmBgYHtyfQpsYXRpbnhfaW1hZ2VBIDwtIGltYWdlX3JlYWQoaGVyZTo6aGVyZSgiaW1nIiwgImxhdGlueF9zdWJfQS5wbmciKSkKbGF0aW54X2ltYWdlQiA8LSBpbWFnZV9yZWFkKGhlcmU6OmhlcmUoImltZyIsICJsYXRpbnhfc3ViX0IucG5nIikpCmxhdGlueF9pbWFnZUMgPC0gaW1hZ2VfcmVhZChoZXJlOjpoZXJlKCJpbWciLCAibGF0aW54X3N1Yl9DLnBuZyIpKQoKbGF0aW54X0EgPC0gaW1hZ2Vfb2NyKGxhdGlueF9pbWFnZUEpCmxhdGlueF9CIDwtIGltYWdlX29jcihsYXRpbnhfaW1hZ2VCKQpsYXRpbnhfQyA8LSBpbWFnZV9vY3IobGF0aW54X2ltYWdlQykKCmBgYAoKPC9kZXRhaWxzPgoKCgpgYGB7ciwgb3V0LndpZHRoPSI0MCUifQpsYXRpbnhfaW1hZ2VBCmxhdGlueF9BCgpsYXRpbnhfaW1hZ2VCCmxhdGlueF9CCgpsYXRpbnhfaW1hZ2VDCmxhdGlueF9DCmBgYApXZSBjYW4gY29tYmluZSB0aGUgc3RyaW5ncyB0b2dldGhlciB1c2luZyB0aGUgYHN0cl9jKClgIGZ1bmN0aW9uICh3aWNoIHN0YW5kcyBmb3Igc3RyaW5nICoqY29sbGFwc2UqKikgb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlLgoKYGBge3J9CmxhdGlueF9zdWJfMjAxNyA8LXN0cmluZ3I6OnN0cl9jKGxhdGlueF9BLCBsYXRpbnhfQiwgbGF0aW54X0MpCgpsYXRpbnhfc3ViXzIwMTcKYGBgCgoKTm93IGxldCdzIGNvcnJlY3QgdGhhdCB0eXBvLgoKIyMjIyB7LnRoaW5rX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KCkhvdyBtaWdodCB5b3UgZG8gdGhpcz8KCiMjIyMKCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4KCgpgYGB7cn0KbGF0aW54X3N1Yl8yMDE3ICU8PiUgCiAgc3RyX3JlcGxhY2Uoc3RyaW5nID0gLiwKICAgICAgICAgICAgIHBhdHRlcm4gPSAiRFIsIEN1YmFuIEZlbWFsZSAxNS43XG5QUiIsCiAgICAgICAgIHJlcGxhY2VtZW50ID0gIkRSLCBDdWJhbiBNYWxlIDE1LjdcblBSIikKYGBgCjwvZGV0YWlscz4KCmBgYHtyfQpsYXRpbnhfc3ViXzIwMTcKYGBgCgoKIyMjIyB7LnJlY2FsbF9jb2RlX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KCkNhbiB5b3UgcmVjYWxsIHRoZSBjb21tYW5kcyB3aXRoaW4gb3VyIGBtYWtlX3Jvd3MoKWAgZnVuY3Rpb24gdG8gc2VwYXJhdGUgdGhlIGRhdGEgaW50byByb3dzIGFuZCBjcmVhdGUgYSB0aWJibGU/CgojIyMjCgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+CgpgYGB7cn0KbGF0aW54X3N1Yl8yMDE3ICU8PiUKICBzdHJfc3BsaXQoIlxuIikgJT4lCiAgdW5saXN0KCkgJT4lCiAgYXNfdGliYmxlKCkKYGBgCjwvZGV0YWlscz4KCmBgYHtyfQpsYXRpbnhfc3ViXzIwMTcKYGBgCk5vdyB3ZSBjYW4gYXBwbHkgb3VyIGZ1bmN0aW9uLiAKCmBgYHtyfQpsYXRpbnhfc3ViXzIwMTcgPC0gY2xlYW5fdGFibGUodGFibGUgPSBsYXRpbnhfc3ViXzIwMTcpCmxhdGlueF9zdWJfMjAxNwpgYGAKCgpJdCBsb29rcyBsaWtlIHdlJ3ZlIHN1Y2Nlc2Z1bGx5IGNvcnJlY3RlZCB0aGUgdHlwbyEKCgpMZXQncyBhbHNvIHJlcGxhY2UgdGhlIGFiYnJldmlhdGlvbnMgZm9yIFB1ZXJ0byBSaWNhbiBhbmQgRG9taW5jYW4gYW5kIGxldCdzIHJlcGxhY2UgTGF0aW5vL0xhdGluYSB3aXRoIExhdGlueC4KCiMjIyMgey50aGlua19xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpIb3cgbWlnaHQgeW91IGRvIHRoaXM/CgojIyMjCgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+CgoKCmBgYHtyfQpsYXRpbnhfc3ViXzIwMTcgJTw+JQogIG11dGF0ZShhY3Jvc3MoLmNvbHMgPSBjKEdyb3VwLCBSYWNlX0V0aG5pY2l0eSksIAogICAgICAgICAgIH5zdHJfcmVwbGFjZShzdHJpbmcgPSAuLAogICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiUHIsIERyLCBDdWJhbiIsCiAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJQdWVydG8gUmljYW4sIERvbWluaWNhbiwgQ3ViYW4iKSksCiAgICAgICAgIGFjcm9zcyguY29scyA9IGMoR3JvdXAsUmFjZV9FdGhuaWNpdHkpLAogICAgICAgICAgfnN0cl9yZXBsYWNlKHN0cmluZyA9IC4sCiAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIkxhdGlub3xMYXRpbmEiLAogICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJMYXRpbngiKSkpCmBgYAoKPC9kZXRhaWxzPgoKCmBgYHtyfQpsYXRpbnhfc3ViXzIwMTcKYGBgCgpHcmVhdCEKCgpOb3cgd2UgYXJlIHJlYWR5IHRvIGxvb2sgYXQgdGhlIGRhdGEgZnJvbSAyMDE4IGZvciB0aGUgQXNpYW4gYW5kIExhdGlueCBzdWJncm91cHMgZnJvbSB0aGUgb3RoZXIgW3JlcG9ydF0oaHR0cHM6Ly9zc3JjLXN0YXRpYy5zMy5hbWF6b25hd3MuY29tL21vYS9BRGVjYWRlVW5kb25lLnBkZikuCgoKIyMjIEFzaWFuIFN1Ymdyb3VwcyAyMDE4CgpSZWNhbGwgdGhhdCB0aGlzIHdhcyB0aGUgcGFnZSB3aXRoIHRoZSB0YWJsZSBvZiBpbnRlcmVzdCBmb3IgdGhlIGFzaWFuIHN1Ymdyb3VwcyB3aXRoIDIwMTggZGF0YToKCmBgYHtyLCBlY2hvID0gRkFMU0UsIH0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImFzaWFuXzIwMThfb3ZlcnZpZXcucG5nIikpCmBgYAoKQXMgeW91IGNhbiBzZWUsIHRoZSBkYXRhIGZvciB0aGUgc3ViZ3JvdXBzIGlzIHNob3duIGluIHRoZSB0YWJsZSBidXQgdGhlIG92ZXJhbGwgZGF0YSBmb3IgQXNpYW5zIGlzIGxvY2F0ZWQgaW4gdGhlIHRleHQuCgpXZSB3aWxsIHVzZSBhIHNjcmVlbnNob3Qgb2YgZWFjaCB0byBleHRyYWN0IHRoZSBkYXRhIGZvciB0aGlzIHllYXIuCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjMwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZy9hc2lhbl9zdWJncm91cHNfMjAxOC5wbmciKSkKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjgwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJhc2lhbl95b3V0aF9leGNlcnB0LnBuZyIpKQpgYGAKVHJpYWwgYW5kIGVycm9yIGluZGljYXRlZCB0aGF0IGFnYWluIGRpdmlkaW5nIHRoZSB0YWJsZSBpbnRvIG11bHRpcGxlIHNjcmVlbnNob3RzIGltcHJvdmVkIHRoZSB0ZXh0IGV4dHJhY3Rpb246CgpgYGB7cn0KYXNpYW5fc3ViXzIwMThfQSA8LSBpbWFnZV9yZWFkKGhlcmU6OmhlcmUoImltZyIsICJhc2lhbl9zdWJfMjAxOF9BLnBuZyIpKQphc2lhbl9zdWJfMjAxOF9BIDwtIGltYWdlX29jcihhc2lhbl9zdWJfMjAxOF9BKQphc2lhbl9zdWJfMjAxOF9CIDwtIGltYWdlX3JlYWQoaGVyZTo6aGVyZSgiaW1nIiwgImFzaWFuX3N1Yl8yMDE4X0IucG5nIikpCmFzaWFuX3N1Yl8yMDE4X0IgPC0gaW1hZ2Vfb2NyKGFzaWFuX3N1Yl8yMDE4X0IpCmFzaWFuX3N1Yl8yMDE4IDwtc3RyX2MoYXNpYW5fc3ViXzIwMThfQSwgYXNpYW5fc3ViXzIwMThfQikKYGBgCgpgYGB7cn0KYXNpYW5fc3ViXzIwMTggPC0gbWFrZV9yb3dzKGFzaWFuX3N1Yl8yMDE4KQoKYXNpYW5fc3ViXzIwMTgKYGBgCk5vdyB3ZSBuZWVkIHRvIG1vZGlmeSBvdXIgZnVuY3Rpb24gYSBiaXQgZm9yIHRoaXMgbmV3IGRhdGEuIAoKRmlyc3RseSwgd2Ugbm93IGhhdmUgY29sb25zIGA6YCBpbiBvdXIgdGFibGUgdGhhdCB3ZSB3aWxsIHdhbnQgdG8gc2VwYXJhdGUgYnkuIFVuZm9ydHVuYXRlbHksIHRoZSB0ZXh0IGluIGVhY2ggcm93IGlzbid0IGV4dHJhY3RlZCBpbiB0aGUgc2FtZSB3YXkgYnkgdGhlIE9DUi5UaHVzIHNvbWUgcm93cyBoYXZlIG9ubHkgYSBzcGFjZSwgd2hpbGUgb3RoZXJzIGhhdmUgc3BhY2VzIGFyb3VuZCBhIGNvbG9uOyBvciBmb3IgdGhlIHJvdyB3aXRoIGBWSUVUTkFNYCB3ZSBzZWUgYSBjb2xvbiBkaXJlY3RseSBhZnRlciB0aGUgd29yZCBmb2xsb3dlZCBieSBhIHNwYWNlLiBUaHVzIHdlIHdpbGwgbW9kaWZ5IG91ciBgc2VwZXJhdGUoKWAgZnVuY3Rpb24gd2l0aCB0aGlzIGNoYW5nZS4gV2UgY2FuIHNwZWNpZnkgIHRoYXQgdGhlIHNlcGFyYXRvciBiZXR3ZWVuIGFueSBsZXR0ZXIgYW5kIGFueSBkaWdpdCBzaG91bGQgYmUgZWl0aGVyIGEgc3BhY2UgKGBcXHNgKSBvciBhIGNvbG9uIHdpdGggYSBzcGFjZSBiZWZvcmUgYW5kIGFmdGVyIGl0IChgXFxzOlxcc2ApIHVzaW5nIHRoZSBvciAoYHxgKW9wcGVyYXRvci4gCgpTbyB0aGlzIHdpbGwgbG9vayBsaWtlIHRoaXM6CgpgYGB7cn0KYXNpYW5fc3ViXzIwMTggJT4lCiAgICBzZXBhcmF0ZSguLCBjb2wgPSB2YWx1ZSwKICAgICAgICAgICAgICAgaW50byA9IGMoIkdyb3VwIiwgIlBlcmNlbnQiKSwgCiAgICAgICAgICAgICAgICBzZXAgPSAgIig/PD1bOmFscGhhOl0pXFxzOlxcc3xcXHMoPz1bMC05XSkiKQoKYGBgClRoZW4gYmVjYXVzZSBvZiB0aGUgcm93IHdpdGggYFZJRVROQU1gLCB3ZSB3aWxsIHdhbnQgdG8gcmVtb3ZlIHRoaXMgY29sb24gdXNpbmcgdGhlIGBzdHJfcmVtb3ZlKClgIGZ1bmN0aW9uIGxpa2UgdGhpczoKCmBgYHtyLCBldmFsID0gRkFMU0V9CmFzaWFuX3N1Yl8yMDE4ICU+JQogICAgc2VwYXJhdGUoLiwgY29sID0gdmFsdWUsIAogICAgICAgICAgICAgICBpbnRvID0gYygiR3JvdXAiLCAiUGVyY2VudCIpLCAKICAgICAgICAgICAgICAgIHNlcCA9ICIoPzw9WzphbHBoYTpdKVxcczpcXHN8XFxzKD89WzAtOV0pIikgJT4lIAogICAgbXV0YXRlKEdyb3VwPSBzdHJfcmVtb3ZlKHN0cmluZyA9IEdyb3VwLCBwYXR0ZXJuID0gIjoiKSkKCmBgYAoKVGhlIG90aGVyIGRpZmZlcmVuY2UgZnJvbSB0aGUgcHJldmlvdXMgZnVuY3Rpb24sIGlzIHRoYXQgd2Ugd2FudCB0byBmaWxsIGluIGEgbmV3IGBSYWNlX0V0aG5pY2l0eWAgdmFyaWFibGUgd2l0aCB0aGUgcHJldmlvdXMgcm93cy4gV2UgY2FuIGRvIHNvIGJ5IGZpcnN0IHJlcGxhY2luZyAiTWVuIiBvciAiV29tZW4iIHdoaWNoIHdpdGggdGhlIG9yIG9wZXJhdG9yIGlzICgiTWVufFdvbWVuIiksIHdpdGggIm1pc3NpbmciLiBUaGVuIHdlIG5lZWQgdG8gY29udmVydCB0aGVzZSB0byBgTkFgIHZhbHVlcyB1c2luZyB0aGUgYG5hX2lmKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UsIHdlIGp1c3QgbmVlZCB0byBzcGVjaWZ5IHdoYXQgY29sdW1uIHRvIG1vZGlmeSBhbmQgd2hhdCB2YWx1ZSB0byBjaGFuZ2UgdG8gYE5BYC4gRmluYWxseSB3ZSB3aWxsIHRoZW4gcmVwYWNlIHRoZSBgTkFgIHZhbHVlcyB3aXRoIHRoZSBwcmV2aW91cyBub24tYE5BYCB2YWx1ZSB1c2luZyB0aGUgYGZpbGwoKWAgZnVuY3Rpb24gb2YgdGhlIGB0aWR5cmAgcGFja2FnZS4gTm90ZSB0aGF0IHRoaXMgZG9lcyBub3Qgd29yayBpbnNpZGUgb2YgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24uIFdlIGp1c3QgbmVlZCB0byBzaW1wbHkgc3BlY2lmeSB3aGF0IGNvbHVtbiB0byBtb2RpZnkgYW5kIHRoZW4gdGhlIGRpcmVjdGlvbiB0byByZXBsYWNlIHZhbHVlcy4gSW4gdGhpcyBjYXNlIHdlIHdhbnQgdG8gcmVwbGFjZSBpbiB0aGUgZG93bndhcmQgZGlyZWN0aW9uIHVzaW5nIHRoZSBwcmV2aW91cyB2YWx1ZXMuIAoKVGhpcyB3aWxsIGxvb2sgbGlrZSB0aGlzOgoKYGBge3J9Cgphc2lhbl9zdWJfMjAxOCAlPiUKc2VwYXJhdGUoLiwgY29sID0gdmFsdWUsIAogICAgICAgICAgIGludG8gPSBjKCJHcm91cCIsICJQZXJjZW50IiksIAogICAgICAgICAgICBzZXAgPSAiKD88PVs6YWxwaGE6XSlcXHM6XFxzfFxccyg/PVswLTldKSIpICU+JQptdXRhdGUoR3JvdXAgPSBzdHJfcmVtb3ZlKHN0cmluZyA9IEdyb3VwLCBwYXR0ZXJuID0gIjoiKSkgJT4lCm11dGF0ZShSYWNlX0V0aG5pY2l0eSA9IHN0cl9yZXBsYWNlKHN0cmluZyA9IEdyb3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiTWVufFdvbWVuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJtaXNzaW5nIikpICU+JQpoZWFkKCkKCmFzaWFuX3N1Yl8yMDE4ICU+JQpzZXBhcmF0ZSguLCBjb2wgPSB2YWx1ZSwgCiAgICAgICAgICAgaW50byA9IGMoIkdyb3VwIiwgIlBlcmNlbnQiKSwgCiAgICAgICAgICAgIHNlcCA9ICIoPzw9WzphbHBoYTpdKVxcczpcXHN8XFxzKD89WzAtOV0pIikgJT4lCm11dGF0ZShHcm91cCA9IHN0cl9yZW1vdmUoc3RyaW5nID0gR3JvdXAsIHBhdHRlcm4gPSAiOiIpKSAlPiUKbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gc3RyX3JlcGxhY2Uoc3RyaW5nID0gR3JvdXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJNZW58V29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIm1pc3NpbmciKSkgJT4lCm11dGF0ZShSYWNlX0V0aG5pY2l0eSA9IG5hX2lmKFJhY2VfRXRobmljaXR5LCAibWlzc2luZyIpKSAlPiUKaGVhZCgpCgphc2lhbl9zdWJfMjAxOCAlPiUKc2VwYXJhdGUoLiwgY29sID0gdmFsdWUsIAogICAgICAgICAgIGludG8gPSBjKCJHcm91cCIsICJQZXJjZW50IiksIAogICAgICAgICAgICBzZXAgPSAiKD88PVs6YWxwaGE6XSlcXHM6XFxzfFxccyg/PVswLTldKSIpICU+JQptdXRhdGUoR3JvdXAgPSBzdHJfcmVtb3ZlKHN0cmluZyA9IEdyb3VwLCBwYXR0ZXJuID0gIjoiKSkgJT4lCm11dGF0ZShSYWNlX0V0aG5pY2l0eSA9IHN0cl9yZXBsYWNlKHN0cmluZyA9IEdyb3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiTWVufFdvbWVuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJtaXNzaW5nIikpICU+JQptdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBuYV9pZihSYWNlX0V0aG5pY2l0eSwgIm1pc3NpbmciKSkgJT4lCmZpbGwoUmFjZV9FdGhuaWNpdHksIC5kaXJlY3Rpb24gPSAiZG93biIpICU+JQpoZWFkKCkKCmBgYAoKT0shIE5vdywgbGV0J3MgY29tYmluZSB0aGVzZSBwaWVjZXMgb2Ygb3VyIG5ldyBmdW5jdGlvbiB3aXRoIHRoZSBvbGQgcGllY2VzOgoKYGBge3J9CgpjbGVhbl90YWJsZSA8LSBmdW5jdGlvbih0YWJsZSl7CiAgdGFibGUgJT4lCiAgICBzZXBhcmF0ZSguLCBjb2wgPSB2YWx1ZSwgCiAgICAgICAgICAgICAgIGludG8gPSBjKCJHcm91cCIsICJQZXJjZW50IiksIAogICAgICAgICAgICAgICAgc2VwID0gICIoPzw9WzphbHBoYTpdKVxcczpcXHN8XFxzKD89WzAtOV0pIikgJT4lIAogICAgbXV0YXRlKEdyb3VwPSBzdHJfcmVtb3ZlKHN0cmluZyA9IEdyb3VwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiOiIpKSAlPiUKICAgIGRyb3BfbmEoKSAlPiUKICAgIG11dGF0ZShHcm91cCA9IHN0cl90b190aXRsZShzdHJpbmcgPSBHcm91cCkpICU+JQogICAgbXV0YXRlKFBlcmNlbnQgPSBzdHJfcmVtb3ZlKHN0cmluZyA9IFBlcmNlbnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJcXC4iKSkgJT4lCiAgICBtdXRhdGUoUGVyY2VudCA9IGFzLm51bWVyaWMoUGVyY2VudCkpICU+JQogICAgbXV0YXRlKFBlcmNlbnQgPSBQZXJjZW50ICogMC4xKSAlPiUKICAgIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9IHN0cl9yZXBsYWNlKHN0cmluZyA9IEdyb3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIk1lbnxXb21lbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIm1pc3NpbmciKSkgJT4lCiAgICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBuYV9pZihSYWNlX0V0aG5pY2l0eSwgIm1pc3NpbmciKSkgJT4lCiAgICBmaWxsKFJhY2VfRXRobmljaXR5LCAuZGlyZWN0aW9uID0gImRvd24iKSAlPiUKICAgIG11dGF0ZShHZW5kZXIgPSBzdHJfZXh0cmFjdChzdHJpbmcgPSBHcm91cCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIk1lbnxXb21lbiIpKSAlPiUKICAgIG11dGF0ZShHZW5kZXIgPSByZXBsYWNlX25hKEdlbmRlciwgcmVwbGFjZSA9ICJBbGwiKSkKfQoKYGBgCgoKYGBge3J9CmFzaWFuX3N1Yl8yMDE4IDwtY2xlYW5fdGFibGUoYXNpYW5fc3ViXzIwMTgpCmFzaWFuX3N1Yl8yMDE4CmBgYAoKTG9va2luZyBnb29kIQoKCk5vdyB3ZSBqdXN0IG5lZWQgdG8gYWRkIHRoZSBkYXRhIGZvciBhbGwgQXNpYW5zIGZyb20gdGhlIHRleHQuIAoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiYXNpYW5feW91dGhfZXhjZXJwdC5wbmciKSkKYGBgCgpXZSBjYW4gZG8gdGhpcyB1c2luZyB0aGUgYGFkZF9yb3coKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cigpYCBwYWNrYWdlLgoKYGBge3J9CmFzaWFuX3N1Yl8yMDE4ICU8PiUKICBhZGRfcm93KEdyb3VwID0gIkFzaWFuIiwKICAgICAgICBQZXJjZW50ID0gNi4yLAogUmFjZV9FdGhuaWNpdHkgPSAiQXNpYW4iLAogICAgICAgICBHZW5kZXIgPSAiQWxsIikgJT4lCiAgYWRkX3JvdyhHcm91cCA9ICJBc2lhbiIsCiAgICAgICAgUGVyY2VudCA9IDYuNCwKIFJhY2VfRXRobmljaXR5ID0gIkFzaWFuIiwKICAgICAgICAgR2VuZGVyID0gIk1lbiIpICU+JQogIGFkZF9yb3coR3JvdXAgPSAiQXNpYW4iLAogICAgICAgIFBlcmNlbnQgPSA2LjEsCiBSYWNlX0V0aG5pY2l0eSA9ICJBc2lhbiIsCiAgICAgICAgIEdlbmRlciA9ICJXb21lbiIpCgphc2lhbl9zdWJfMjAxOApgYGAKCk9LLCBub3cgd2UganVzdCB3YW50IHRvIGNvbWJpbmUgdGhlIDIwMTggZGF0YSBhbmQgdGhlIDIwMTcgZGF0YSBmb3IgdGhlIGFzaWFuIHN1Ymdyb3Vwcy4KCkZpcnN0IGxldCdzIGFkZCBhIHZhcmFpYmxlIGZvciB5ZWFyIHRvIGJvdGguIFVzaW5nIGBtdXRhdGUoKWAgd2UgY2FuIGFkZCBhIHZhcmlhYmxlIGBZZWFyYCB3aGVyZSBhbGwgdmFsdWVzIGFyZSBgMjAxN2AgbGlrZSBzbzoKCmBgYHtyfQphc2lhbl9zdWJfMjAxNyAlPD4lCiAgbXV0YXRlKFllYXIgPSAyMDE3KQphc2lhbl9zdWJfMjAxNyAKYGBgCgpgYGB7cn0KYXNpYW5fc3ViXzIwMTggJTw+JQogIG11dGF0ZShZZWFyID0gMjAxOCkKYXNpYW5fc3ViXzIwMTgKYGBgCgpZb3UgbWF5IG5vdGljZSB0aGF0IGBHZW5kZXJgIGlzIGNvZGVkIGRpZmZlcmVudGx5IGZvciB0aGUgdHdvIHllYXJzLiBMZXQncyBtYWtlIHRoaXMgY29uc2lzdGVudCBub3c6CgpgYGB7cn0KYXNpYW5fc3ViXzIwMTggJTw+JQogIG11dGF0ZShhY3Jvc3MoLmNvbHMgPSBjKEdlbmRlciwgR3JvdXApLAogICAgICAgICAgICAgICB+IHN0cl9yZXBsYWNlKHN0cmluZyA9IC4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJNZW4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiTWFsZSIpKSwKICAgICAgICAgYWNyb3NzKC5jb2xzID0gYyhHZW5kZXIsIEdyb3VwKSwKICAgICAgICAgICAgICAgfiBzdHJfcmVwbGFjZShzdHJpbmcgPSAuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiRmVtYWxlIikpKQoKYGBgCgpXZSBjYW4gY29tYmluZSB0aGVzZSB0d28gdGliYmxlcyB1c2luZyB0aGUgYGJpbmRfcm93cygpYCBmdW5jdGlvbiBvZiBgZHBseXJgLiAKCmBgYHtyfQoKYXNpYW5fc3ViZ3JvdXBzIDwtIGJpbmRfcm93cyhhc2lhbl9zdWJfMjAxNywgYXNpYW5fc3ViXzIwMTgpCmBgYAoKCmBgYHtyLCBlY2hvID0gRkFMU0V9CkRUOjpkYXRhdGFibGUoYXNpYW5fc3ViZ3JvdXBzKQpgYGAKCgoKTm90aWNlIHRoYXQgdGhlcmUgYXJlIHNvbWUgY2FzZXMgd2hlcmUgd2Ugb25seSBoYXZlIG9uZSB2YWx1ZSBmb3IgYSBwcmF0aWN1bGFyIGdyb3VwLiBGb3IgZXhhbXBsZSwgdGhlcmUgYXJlIG5vIG1hbGUgb3IgZmVtYWxlIHZhbHVlcyBmb3IgdGhlIFBha2lzdGFuaSBkYXRhLgoKV2Ugd291bGQgbGlrZSB0byBoYXZlIGBOQWAgdmFsdWVzIGZvciB0aGUgY29tcHJhYmxlIHllYXJzL2dlbmRlcnMgdGhhdCBhcmUgcG9zc2libGUuIFdlIGNhbiBmaWxsIG91dCB0aGUgcmVzdCBvZiB0aGUgdGFibGUgd2l0aCBgTkFgIHZhbHVlcyBieSBwZXJmb3JtaW5nIHRoZSBgcGl2b3Rfd2lkZXIoKWAgYW5kIGBwaXZvdF9sb25nZXIoKWAgZnVuY3Rpb25zIHNlcXVlbnRpYWxseSBsaWtlIHNvOgoKYGBge3IsIGV2YWw9RkFMU0V9Cgphc2lhbl9zdWJncm91cHMgJTw+JSAKc2VsZWN0KC1Hcm91cCkgJT4lCnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZZWFyLCB2YWx1ZXNfZnJvbSA9IFBlcmNlbnQpICU+JQpwaXZvdF9sb25nZXIoY29scyA9IC1jKFJhY2VfRXRobmljaXR5LCBHZW5kZXIpLCAKbmFtZXNfdG8gPSJZZWFyIiAsIAp2YWx1ZXNfdG89IlBlcmNlbnQiKQpgYGAKCgpgYGB7ciwgZWNobyA9IEZBTFNFfQpEVDo6ZGF0YXRhYmxlKGFzaWFuX3N1Ymdyb3VwcykKYGBgCgoKR3JlYXQsIG5vdyB3ZSBhcmUgcmVhZHkgdG8gcGVmb3JtIHNpbWlsYXIgd3JhbmdsaW5nIGZvciB0aGUgTGF0aW54IHN1Ymdyb3Vwcy4KCiMjIyBMYXRpbnggU3ViZ3JvdXBzIDIwMTggCgpSZWNhbGwgdGhhdCB0aGlzIHdhcyB0aGUgcGFnZSB3aXRoIHRoZSB0YWJsZSBvZiBpbnRlcmVzdCBmb3IgdGhlIExhdGlueCBzdWJncm91cCAyMDE4IGRhdGE6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCB9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJsYXRpbnhfMjAxOF9vdmVydmlldy5wbmciKSkKYGBgCgpJbiB0aGlzIGNhc2Ugb25seSBhIHNpbmdsZSBpbWFnZSB3YXMgbmVlZGVkOgoKYGBge3J9CmxhdGlueF9zdWJfMjAxOCA8LSBpbWFnZV9yZWFkKGhlcmU6OmhlcmUoImltZyIsICJsYXRpbnhfc3ViZ3JvdXBzXzIwMTgucG5nIikpCmxhdGlueF9zdWJfMjAxOCA8LSBpbWFnZV9vY3IobGF0aW54X3N1Yl8yMDE4KQpsYXRpbnhfc3ViXzIwMTgKYGBgCgpMZXQncyBmaXJzdCBjb21iaW5lIHRoZSBTb3V0aCBhbmQgQ2VudHJhbCBBbWVyaWNhbiBsYWJlbHMuIE5vdGljZSB0aGF0IHRoZXJlIGFyZSBtdWx0aXBsZSBuZXcgbGluZSBleHByZXNzaW9ucyBpbiBiZXR3ZWVuIGFuZCB3ZSBkb250IHNlZSByZXBlYXRlZCBgXG5gIGNoYXJhY3RlcnMgZWxzZXdoZXJlLgpXZSBjYW4gcmVwbGFjZSB0aGUgcGF0dGVybiBvZiBleGFjdGx5IHR3byBgXG5gICh1c2luZyBgXG57Mn1gIHRvIHNwZWNpZnkgZXhhY3RseSAyKSBvciB0d28gbmV3bGluZSByZWdleCB3aXRoIGEgc3BhY2UgYW5kIGNvbG9uIGluIGZyb250IHdpdGggYSBzaW5nbGUgc3BhY2UuCgpgYGB7cn0KbGF0aW54X3N1Yl8yMDE4IDwtIHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSBsYXRpbnhfc3ViXzIwMTgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJcXHM6XG57Mn18XG57Mn0iLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiICIpCmxhdGlueF9zdWJfMjAxOCAKYGBgCgoKYGBge3J9CmxhdGlueF9zdWJfMjAxOCA8LSBtYWtlX3Jvd3MobGF0aW54X3N1Yl8yMDE4ICkKCmxhdGlueF9zdWJfMjAxOApgYGAKCgpgYGB7cn0KbGF0aW54X3N1Yl8yMDE4IDwtY2xlYW5fdGFibGUobGF0aW54X3N1Yl8yMDE4KQpsYXRpbnhfc3ViXzIwMTgKYGBgCgoKQWdhaW4gd2Ugd2lsbCByZXBsYWNlIGBQciwgRHIsIEN1YmFuYDoKYGBge3J9CmxhdGlueF9zdWJfMjAxOCAlPD4lCiAgbXV0YXRlKEdyb3VwID0gCiAgICAgICAgICAgc3RyX3JlcGxhY2Uoc3RyaW5nID0gR3JvdXAsCiAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIlByLCBEciwgQ3ViYW4iLAogICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJQdWVydG8gUmljYW4sIERvbWluaWNhbiwgQ3ViYW4iKSwgCiAgICAgICAgICBSYWNlX0V0aG5pY2l0eSA9IAogICAgICAgICAgIHN0cl9yZXBsYWNlKHN0cmluZyA9IFJhY2VfRXRobmljaXR5LAogICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJQciwgRHIsIEN1YmFuIiwKICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiUHVlcnRvIFJpY2FuLCBEb21pbmljYW4sIEN1YmFuIikpCgpgYGAKCgoKV2UgYWxzbyB3YW50IHRvIGFkZCB0aGUgdG90YWwgTGF0aW54IHZhbHVlcyBhY2NvcmRpbmcgdG8gdGhlIHRleHQ6CgoKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAibGF0aW54X3lvdXRoX2V4Y2VycHQucG5nIikpCgpgYGAKCgojIyMjIHsucmVjYWxsX2NvZGVfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKQ2FuIHlvdSByZWNhbGwgaG93IHRvIGFkZCBhZGRpdGlvbmFsIHJvd3M/CgojIyMjCgoKPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHJldmVhbCB0aGUgY29kZS4gPC9zdW1tYXJ5PgoKCmBgYHtyfQpsYXRpbnhfc3ViXzIwMTggJTw+JQogIGFkZF9yb3coR3JvdXAgPSAiTGF0aW54IiwKICAgICAgICBQZXJjZW50ID0gMTIuOCwKIFJhY2VfRXRobmljaXR5ID0gIkxhdGlueCIsCiAgICAgICAgIEdlbmRlciA9ICJBbGwiKSAlPiUKICBhZGRfcm93KEdyb3VwID0gIkxhdGlueCIsCiAgICAgICAgUGVyY2VudCA9IDEyLjMsCiBSYWNlX0V0aG5pY2l0eSA9ICJMYXRpbngiLAogICAgICAgICBHZW5kZXIgPSAiTWVuIikgJT4lCiAgYWRkX3JvdyhHcm91cCA9ICJMYXRpbngiLAogICAgICAgIFBlcmNlbnQgPSAxMy4zLAogUmFjZV9FdGhuaWNpdHkgPSAiTGF0aW54IiwKICAgICAgICAgR2VuZGVyID0gIldvbWVuIikKYGBgCgo8L2RldGFpbHM+CgoKYGBge3J9CnRhaWwobGF0aW54X3N1Yl8yMDE4KQpgYGAKCkFuZCBub3cgd2Ugd2lsbCByZWNvZGUgZ2VuZGVyIGxpa2UgYmVmb3JlIHRvIGJlIGNvbnNpc3RlbnQ6CgpgYGB7cn0KbGF0aW54X3N1Yl8yMDE4ICU8PiUKICBtdXRhdGUoYWNyb3NzKC5jb2xzID0gYyhHZW5kZXIsIEdyb3VwKSwKICAgICAgICAgICAgICAgIH4gc3RyX3JlcGxhY2Uoc3RyaW5nID0gLiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJNZW4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIk1hbGUiKSksCiAgICAgICAgIGFjcm9zcyguY29scyA9IGMoR2VuZGVyLCBHcm91cCksCiAgICAgICAgICAgICAgICB+IHN0cl9yZXBsYWNlKHN0cmluZyA9IC4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiV29tZW4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIkZlbWFsZSIpKSkKCmhlYWQobGF0aW54X3N1Yl8yMDE4KQpgYGAKCgoKTm93IHdlIGp1c3QgbmVlZCB0byBjb21iaW5lIGFsbCB0aGUgZGF0YSBmb3IgdGhlIExhdGlueCBzdWJncm91cHMuCgoKQWdhaW4sIGZpcnN0IHdlIHdpbGwgYWRkIGEgeWVhciB2YXJpYWJsZSB0byBib3RoIHRoZSAyMDE3IGFuZCAyMDE4IGRhdGEuCgpgYGB7cn0KbGF0aW54X3N1Yl8yMDE3ICU8PiUKICBtdXRhdGUoWWVhciA9IDIwMTcpCgpsYXRpbnhfc3ViXzIwMTggJTw+JQogIG11dGF0ZShZZWFyID0gMjAxOCkKCmxhdGlueF9zdWJncm91cHMgPC0gYmluZF9yb3dzKGxhdGlueF9zdWJfMjAxNywgbGF0aW54X3N1Yl8yMDE4KQpsYXRpbnhfc3ViZ3JvdXBzCmBgYAoKCkFnYWluLCB3ZSB3b3VsZCBsaWtlIHRvIGhhdmUgYE5BYCB2YWx1ZXMgZm9yIHRoZSBjb21wcmFibGUgeWVhcnMvZ2VuZGVycyB0aGF0IGFyZSBwb3NzaWJsZS4gV2Ugd2lsbCBmaWxsIG91dCB0aGUgcmVzdCBvZiB0aGUgdGFibGUgd2l0aCBgTkFgIHZhbHVlcyBieSBwZXJmb3JtaW5nIHRoZSBgcGl2b3Rfd2lkZXIoKWAgYW5kIGBwaXZvdF9sb25nZXIoKWAgZnVuY3Rpb25zIHNlcXVlbnRpYWxseSBsaWtlIHNvOgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KCmxhdGlueF9zdWJncm91cHMgJTw+JSAKc2VsZWN0KC1Hcm91cCkgJT4lCnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZZWFyLCB2YWx1ZXNfZnJvbSA9IFBlcmNlbnQpICU+JQpwaXZvdF9sb25nZXIoY29scyA9IC1jKFJhY2VfRXRobmljaXR5LCBHZW5kZXIpLCAKbmFtZXNfdG8gPSJZZWFyIiAsIAp2YWx1ZXNfdG89IlBlcmNlbnQiKQpgYGAKCgpgYGB7ciwgZWNobyA9IEZBTFNFfQpEVDo6ZGF0YXRhYmxlKGFzaWFuX3N1Ymdyb3VwcykKYGBgCgojIyMgQ2hlY2tpbmcgdGhlIGRhdGEKCk9LLCBub3cgbGV0J3MgbWFrZSBzdXJlIHRoYXQgb3VyIG5vdGF0aW9ucyBtYXRjaCBhY3Jvc3Mgb3VyIGRpZmZlcmVudCB0YWJsZXMuIEZvciBleGFtcGxlIGluIHRoZSBmaXJzdCByZXBvcnQgdGhlIHRlcm1zIG1hbGUgYW5kIGZlbWFsZSB3aGVyZSB1c2VkLCBidXQgaW4gdGhlIHNlY29uZCByZXBvcnQgbWVuIGFuZCB3b21lbiB3ZXJlIHVzZWQuIExldCdzIG1ha2Ugc3VyZSBldmVyeXRoaW5nIGlzIGNvbnNpc3RlbnQgbm93LgoKYGBge3J9Cm1ham9yX2dyb3Vwc19sb25nCmFzaWFuX3N1Ymdyb3VwcwpsYXRpbnhfc3ViZ3JvdXBzCmBgYAoKTG9va3MgZ29vZCEKCmBgYHtyLCBlY2hvPSBGQUxTRSwgZXZhbCA9IFRSVUV9CnNhdmUobWFqb3JfZ3JvdXBzX2xvbmcsIGFzaWFuX3N1Ymdyb3VwcywgbGF0aW54X3N1Ymdyb3VwcywKICAgICBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZF9kYXRhLnJkYSIpKQoKYGBgCgojIyAqKkRhdGEgVmlzdWFsaXphdGlvbioqCioqKiAKClJlY2FsbCB3aGF0IG91ciBtYWluIHF1ZXN0aW9ucyB3ZXJlPwoKCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gT3VyIG1haW4gcXVlc3Rpb25zOiA8L3U+PC9iPgoKMSkgSG93IGhhdmUgeW91dGggZGlzY29ubmVjdGlvbiByYXRlcyBpbiBBbWVyaWNhbiB5b3V0aCBjaGFuZ2VkIHNpbmNlIDIwMDg/ICAgCjIpIEluIHBhcnRpY3VsYXIsIGhvdyBoYXMgdGhpcyBjaGFuZ2VkIGZvciBkaWZmZXJlbnQgZ2VuZGVyIGFuZCBldGhuaWMgZ3JvdXBzPyBBcmUgYW55IGdyb3VwcyBwYXJ0aWN1bGFybHkgZGlzY29ubmVjdGVkPyAKCiMjIyMKCk5vdyB0aGF0IHdlIGhhdmUgd3JhbmdsZWQgb3VyIGRhdGEgYW5kIG1hZGUgaXQgZWFzeSB0byB3b3JrIHdpdGgsIGxldCdzIGNyZWF0ZSBzb21lIHZpc3VhbGl6YXRpb25zIHRvIGV4cGxvcmUgdGhlc2UgcXVlc3Rpb25zLgoKYGBge3IsIGVjaG8gPSBGQUxTRX0KIyBUbyBhbGxvdyBzdGFydGluZyBhdCB0aGlzIHNlY3Rpb246CmxvYWQoaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZF9kYXRhLnJkYSIpKQpgYGAKCgoKIyMjIE1ham9yIFJhY2UgYW5kIEV0aG5pYyBHcm91cHMgUGxvdAoKV2UgYXJlIHBhcnRpY3VsYXJseSBpbnRlcmVzdGVkIGluIGJlaW5nIGFibGUgdG8gcmVwcm9kdWNlIHRoZSBwbG90IGJlbG93LCBhcyB3ZSB3b3VsZCBsaWtlIHRvIG1ha2Ugc2ltaWxhciBsb29raW5nIHBsb3RzLgoKYGBge3IsIG91dC53aWR0aCA9ICIxMDAlIiwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIifQppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJNYWtpbmdfdGhlX0Nvbm5lY3Rpb25fcGxvdC5wbmciKSkKYGBgCgpJbiBnZW5lcmFsLCBpdCBpcyB2ZXJ5IHVzZWZ1bCB0byBsZWFybiBob3cgdG8gcmVwcm9kdWNlIHRoZSBzdHlsZSBvZiBhIHBsb3QuCgoKVGhlcmUgYXJlIGNvbG9yIGlkZW50aWZ5aW5nIHdlYnNpdGVzIHN1Y2ggYXMgW3RoaXNdKGh0dHBzOi8vaW1hZ2Vjb2xvcnBpY2tlci5jb20vZW4vKS4KClVzaW5nIG9uZSBvZiB0aGVzZSB3ZWJzaXRlcywgd2UgaWRlbnRpZnkgdGhlIFtoZXggdHJpcGxldF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvV2ViX2NvbG9ycz9vbGRmb3JtYXQ9dHJ1ZSkgY29kZSBmb3IgdGhlIGNvbG9yIHVzZWQgaW4gdGhlIHZpc3VhbGl6YXRpb24gaW5jbHVkZWQgaW4gdGhlIFBERiA6IGAjMDA4MzkzYC4gIFRodXMgd2Ugd2lsbCB1c2UgdGhpcyBjb2xvciBvdXIgcGxvdC4KCgpXZSBjYW4gY3JlYXRlIGEgdmVyc2lvbiBvZiB0aGUgYWJvdmUgcGxvdCB1c2luZyB0aGUgYGdncGxvdDJgIHBhY2thZ2Ugb2YgdGhlIF90aWR5dmVyc2VfIHRvIGNyZWF0ZSBvdXIgcGxvdHMuCgoqKioKPGRldGFpbHM+PHN1bW1hcnk+IENsaWNrIGhlcmUgZm9yIGFuIGludHJvZHVjdGlvbiBhYm91dCB0aGlzIHBhY2thZ2UgaWYgeW91IGFyZSAgbmV3IHRvIHVzaW5nIGBnZ3Bsb3QyYCA8L3N1bW1hcnk+CgpUaGUgW2dncGxvdDIgcGFja2FnZV0oaHR0cDovL2dncGxvdDIudGlkeXZlcnNlLm9yZykgaXMgZ2VuZXJhbGx5IGludHVpdGl2ZSBmb3IgYmVnaW5uZXJzIGJlY2F1c2UgaXQgaXMgYmFzZWQgb24gYSAgW2dyYW1tYXIgb2YgZ3JhcGhpY3NdKGh0dHA6Ly92aXRhLmhhZC5jby5uei9wYXBlcnMvbGF5ZXJlZC1ncmFtbWFyLmh0bWwpIG9yIHRoZSBgZ2dgIGluIGBnZ3Bsb3QyYC4gClRoZSBpZGVhIGlzIHRoYXQgeW91IGNhbiBjb25zdHJ1Y3QgbWFueSBzZW50ZW5jZXMgYnkgbGVhcm5pbmcganVzdCBhIGZldyBub3VucywgYWRqZWN0aXZlcywgYW5kIHZlcmJzLiBUaGVyZSBhcmUgc3BlY2lmaWMg4oCcd29yZHPigJ0gdGhhdCB3ZSB3aWxsIG5lZWQgdG8gbGVhcm4gYW5kIG9uY2Ugd2UgZG8sIHlvdSB3aWxsIGJlIGFibGUgdG8gY3JlYXRlIChvciDigJx3cml0ZeKAnSkgaHVuZHJlZHMgb2YgZGlmZmVyZW50IHBsb3RzLgoKVGhlIGNyaXRpY2FsIHBhcnQgdG8gbWFraW5nIGdyYXBoaWNzIHVzaW5nIGBnZ3Bsb3QyYCBpcyB0aGUgZGF0YSBuZWVkcyB0byBiZSBpbiBhIF90aWR5XyBmb3JtYXQuIApHaXZlbiB0aGF0IHdlIGhhdmUganVzdCBzcGVudCB0aW1lIHB1dHRpbmcgb3VyIGRhdGEgaW4gX3RpZHlfIGZvcm1hdCwgd2UgYXJlIHByaW1lZCB0byB0YWtlIGFkdmFudGFnZSBvZiBhbGwgdGhhdCBgZ2dwbG90MmAgaGFzIHRvIG9mZmVyISAKCldlIHdpbGwgc2hvdyBob3cgaXQgaXMgZWFzeSB0byBwaXBlIF90aWR5XyBkYXRhIChvdXRwdXQpIGFzIGlucHV0IHRvIG90aGVyIGZ1bmN0aW9ucyB0aGF0IGNyZWF0ZSBwbG90cy4gClRoaXMgYWxsIHdvcmtzIGJlY2F1c2Ugd2UgYXJlIHdvcmtpbmcgCndpdGhpbiB0aGUgX3RpZHl2ZXJzZV8uIAoKKipXaGF0IGlzIHRoZSBgZ2dwbG90KClgIGZ1bmN0aW9uPyoqIApBcyBleHBsYWluZWQgYnkgSGFkbGV5IFdpY2toYW06Cgo+IFRoZSBncmFtbWFyIHRlbGxzIHVzIHRoYXQgYSBzdGF0aXN0aWNhbCBncmFwaGljIGlzIGEgbWFwcGluZyBmcm9tIGRhdGEgdG8gYWVzdGhldGljIGF0dHJpYnV0ZXMgKGNvbG91ciwgc2hhcGUsIHNpemUpIG9mIGdlb21ldHJpYyBvYmplY3RzIChwb2ludHMsIGxpbmVzLCBiYXJzKS4gVGhlIHBsb3QgbWF5IGFsc28gY29udGFpbiBzdGF0aXN0aWNhbCB0cmFuc2Zvcm1hdGlvbnMgb2YgdGhlIGRhdGEgYW5kIGlzIGRyYXduIG9uIGEgc3BlY2lmaWMgY29vcmRpbmF0ZXMgc3lzdGVtLgoKYGdncGxvdDJgIFRlcm1pbm9sb2d5OiAKCi0gKipnZ3Bsb3QqKiAtIHRoZSBtYWluIGZ1bmN0aW9uIHdoZXJlIHlvdSBzcGVjaWZ5IHRoZSBkYXRhc2V0IGFuZCB2YXJpYWJsZXMgdG8gcGxvdCAodGhpcyBpcyB3aGVyZSB3ZSBkZWZpbmUgdGhlIGB4YCBhbmQKYHlgIHZhcmlhYmxlIG5hbWVzKQotICoqZ2VvbXMqKiAtIGdlb21ldHJpYyBvYmplY3RzCiAgICAtIGUuZy4gYGdlb21fcG9pbnQoKWAsIGBnZW9tX2JhcigpYCwgYGdlb21fbGluZSgpYCwgYGdlb21faGlzdG9ncmFtKClgCi0gKiphZXMqKiAtIGFlc3RoZXRpY3MKICAgIC0gc2hhcGUsIHRyYW5zcGFyZW5jeSwgY29sb3IsIGZpbGwsIGxpbmUgdHlwZXMKLSAqKnNjYWxlcyoqIC0gZGVmaW5lIGhvdyB5b3VyIGRhdGEgd2lsbCBiZSBwbG90dGVkCiAgICAtIGNvbnRpbnVvdXMsIGRpc2NyZXRlLCBsb2csIGV0YwoKVGhlIGZ1bmN0aW9uIGBhZXMoKWAgaXMgYW4gYWVzdGhldGljIG1hcHBpbmcgZnVuY3Rpb24gaW5zaWRlIHRoZSBgZ2dwbG90KClgIG9iamVjdC4gCldlIHVzZSB0aGlzIGZ1bmN0aW9uIHRvIHNwZWNpZnkgcGxvdCBhdHRyaWJ1dGVzIChlLmcuIGB4YCBhbmQgYHlgIHZhcmlhYmxlIG5hbWVzKSB0aGF0IHdpbGwgbm90IGNoYW5nZSBhcyB3ZSBhZGQgbW9yZSBsYXllcnMuICAKCkFueXRoaW5nIHRoYXQgZ29lcyBpbiB0aGUgYGdncGxvdCgpYCBvYmplY3QgYmVjb21lcyBhIGdsb2JhbCBzZXR0aW5nLiAKRnJvbSB0aGVyZSwgd2UgdXNlIHRoZSBgZ2VvbWAgb2JqZWN0cyB0byBhZGQgbW9yZSBsYXllcnMgdG8gdGhlIGJhc2UgYGdncGxvdCgpYCBvYmplY3QuIApUaGVzZSB3aWxsIGRlZmluZSB3aGF0IHdlIGFyZSBpbnRlcmVzdGVkIGluIGlsbHVzdHJhdGluZyB1c2luZyB0aGUgZGF0YS4KCjwvZGV0YWlscz4KCioqKgoKU28gZm9yIHRoaXMgZmlyc3QgcGxvdCB3ZSBqdXN0IHdhbnQgdG8gcmVjcmVhdGUgdGhlIHBsb3QgaW4gdGhlIFBERi4gVGh1cyB3ZSB3aWxsIHVzZSB0aGUgYG1ham9yX2dyb3Vwc19sb25nYCB0aWJibGUgYW5kIHdlIHdpbGwgZmlsdGVyIGZvciB0aGUgYCJBbGwiYCB2YWx1ZXMgb2YgdGhlIGBHZW5kZXJgIHBhY2thZ2UuIFdlIGFsc28gd2FudCB0byBleGNsdWRlIHRoZSBkYXRhIGZvciB0aGUgVW5pdGVkIHN0YXRlcy4gCldlIGNhbiBleGNsdWRlIHRoZSBkYXRhIGZyb20gdGhlIFVTIHVzaW5nIHRoZSBub3QgZXF1YWxzIGAhPWAgb3BwZXJhdG9yIGxpa2Ugc286CgpgYGB7cn0KbWFqb3JfZ3JvdXBzX2xvbmcgJT4lCiAgIGZpbHRlcihHZW5kZXIgPT0gIkFsbCIsCiAgICAgICAgICBHcm91cCAhPSAiVW5pdGVkIFN0YXRlcyIpCmBgYAoKVGhlIGRhdGEgZnJvbSB0aGUgdGFibGVzIG9ubHkgaW5jbHVkZWQgdXAgdG8gMjAxNywgYnV0IHRoaXMgd2lsbCBzdGlsbCBhbGxvdyB1cyB0byBjcmVhdGUgYSBzaW1pbGFyIHBsb3QuCgpOb3cgd2UgaGF2ZSB0aGUgZGF0YSByZWFkeSB0byBtYWtlIHRoZSBwbG90Li4uIGJ1dCBob3cgZG8gd2UgYWN0dWFsbHkgc3RhcnQgbWFraW5nIHRoZSBwbG90PwoKRmlyc3QsIHdlIHN0YXJ0IHdpdGggdGhlIGBnZ3Bsb3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlLgoKVGhpcyBmdW5jdGlvbiByZXF1aXJlcyB0aGF0IHRoZSBhZXN0aGV0aWNzIGBhZXMoKWAgYmUgc3BlY2lmaWVkLiBUaGlzIGludm9sdmVzIGNob29zaW5nIHdoYXQgdmFyaWFibGUgd2lsbCBiZSBwbG90dGVkIG9uIHRoZSB4LWF4aXMgYW5kIHRoZSB5IGF4aXMuIEl0IGFsc28gaW52b2x2ZXMgY2hvb3NpbmcgdmFyaWFibGVzIHRvIGNvbG9yIG9yIGdyb3VwIG91ciBwbG90IGJ5LiAKCkluIG91ciBjYXNlLCB3ZSB3YW50IHRvIHBsb3QgdGhlIHBlcmNlbnQgb2YgZGlzY29ubmVjdGlvbiBvbiB0aGUgeS1heGlzICh0aHVzIHRoZSBgUGVyY2VudGAgdmFyYWlibGUgb2YgdGhlIGBtYWpvcl9ncm91cHNfbG9uZ2AgZGF0YSkgYW5kIHRoZSBZZWFyIG9uIHRoZSB4LWF4aXMuIFdlIHdvdWxkIGxpa2UgdG8gc2VwYXJhdGUgZWFjaCByYWNpYWwgb3IgZXRobmljIGdyb3VwIHRvIGhhdmUgdGhlaXIgb3duIHBvaW50cy9saW5lcy4gVGh1cyB3ZSB3aWxsIHVzZSB0aGUgYGNvbG9yYCBhcmd1bWVudCBmb3IgdGhpcyB2YXJpYWJsZSB0byBkbyB0aGlzLCBhcyB3ZSBpbnRlbmQgdG8gY29sb3Igb3VyIHBsb3Qgc29tZXRoaW5nIG90aGVyIHRoYW4gYmxhY2suCgpJZiB3ZSBydW4gdGhlIGZvbGxvd2luZyBjb2RlLCB3ZSBnZXQgYW4gZW1wdHkgcGxvdC4KCmBgYHtyLCBldmFsID0gRkFMU0V9Cm1ham9yX2dyb3Vwc19sb25nICU+JQogICBmaWx0ZXIoR2VuZGVyID09ICJBbGwiLAogICAgICAgICAgR3JvdXAgIT0gIlVuaXRlZCBTdGF0ZXMiKSAlPiUKZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IFBlcmNlbnQsIGNvbG9yID0gUmFjZV9FdGhuaWNpdHkpKQoKYGBgCgoKVGhlIG5leHQgdGhpbmcgd2UgbmVlZCB0byBkbyBpcyBhZGQgYGdncGxvdDJgIGxheWVycyB1c2luZyB0aGUgYCtgIHRvIHNwZWNpZnkgaG93IHdlIHdhbnQgdGhlIGRhdGEgdG8gYmUgZGlzcGxheWVkIG9uIG91ciBwbG90LgoKV2Ugd291bGQgbGlrZSBib3RoIHBvaW50cyBhbmQgbGluZXMuIFdlIHdpbGwgdXNlIHRoZSBgZ2VvbV9wb2ludCgpYCBhbmQgYGdlb21fbGluZSgpYCBmdW5jdGlvbnMgb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIHRvIGRvIHRoaXMuIFdoaWNoIGV2ZXIgbGF5ZXIgd2UgYWRkIGZpcnN0IHdpbGwgYmUgcGxvdHRlZCBmaXJzdCBhbmQgdGhlcmVmb3JlIGJlbG93IHRoZSBuZXh0IGxheWVyLiBXZSB3aWxsIGFsc28gc3BlY2lmeSB0aGUgc2l6ZSBvZiB0aGVzZSBlbGVtZW50cyB1c2luZyB0aGUgYHNpemVgIGFyZ3VtZW50LgoKYGBge3J9CgptYWpvcl9ncm91cHNfbG9uZyAlPiUKICAgZmlsdGVyKEdlbmRlciA9PSAiQWxsIiwKICAgICAgICAgIEdyb3VwICE9ICJVbml0ZWQgU3RhdGVzIikgJT4lCmdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCBjb2xvciA9IFJhY2VfRXRobmljaXR5KSkgKwogIGdlb21fbGluZShzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgCgpgYGAKCgpPSywgbm90IGJhZCwgYnV0IHdlIGhhdmUgcXVpdGUgYSBiaXQgdG8gd29yayBvbiB0byBtYWtlIHRoZSBzdHlsZSBtYXRjaC4KCkZpcnN0LCB3ZSB3aWxsIHVwZGF0ZSB0aGUgeC1heGlzIGFuZCB5LWF4aXMsIHRvIGxvb2sgbW9yZSBzaW1pbGFyIHRvIHRoZSBwbG90IGZyb20gdGhlIHJlcG9ydC4gV2UgY2FuIHNwZWNpZnkgd2hlcmUgdGhlIHRpY2sgbWFya3Mgc2hvdWxkIGJlIGZvciBlYWNoIHVzaW5nIGBicmVha3NgIGFyZ3VtZW50IG9mIHRoZSBgc2NhbGVfeF9jb250aW51b3VzKClgIGFuZCBgc2NhbGVfeV9jb250aW51b3VzKClgIGZ1bmN0aW9ucyAoYWxzbyBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UpLiBUaGVzZSBmdW5jdGlvbnMgYWxzbyBhbGxvdyBmb3Igc3BlY2lmaWNhdGlvbiBvZiB0aGUgcmFuZ2Ugb3IgbGltaXRzIG9mIHRoZSBheGlzIHVzaW5nIHRoZSBgbGltaXRzYCBhcmd1bWVudC4gV2UgY2FuIHVzZSB0aGUgYmFzZSBgc2VxKClgIGZ1bmN0aW9uIHRvIGNyZWF0ZSBhIHNlcXVlbmNlIG9mIG51bWJlcnMgZm9yIGVhY2ggdGljayBtYXJrLgpXZSB3aWxsIG1ha2UgdGhlIHgtYXhpcyB1cHBlciBsaW1pdCBhIGJpdCBsYXJnZXIgdG8gYWxsb3cgZm9yIHRoZSBpbWFnZSBvZiB0aGUgZmlndXJlIGFuZCB0aGUgbGFiZWwgZm9yIGVhY2ggZ3JvdXAuCgpOZXh0LCB3ZSB3aWxsIGNoYW5nZSB0aGUgY29sb3IgdG8gbWF0Y2ggdGhlIG9uZSB0aGF0IHdlIGlkZW50aWZpZWQsIGJ5IHVzaW5nIHRoZSBgc2NhbGVfY29sb3JfbWFudWFsKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4gVGhpcyByZXF1aXJlcyBjb2xvciB2YWx1ZXMgZm9yIGVhY2ggZ3JvdXAuIEluIG91ciBjYXNlLCB3ZSBoYXZlIDUgZ3JvdXBzLCBzbyB3ZSByZXBlYXRlIHRoaXMgdmFsdWUgNSB0aW1lcyB1c2luZyB0aGUgYmFzZSBgcmVwKClgIGZ1bmN0aW9uLgoKV2Ugd2lsbCBhbHNvIGNoYW5nZSB0aGUgb3ZlcmFsbCBsb29rIG9mIHRoZSBwbG90IHVzaW5nIHRoZSBgdGhlbWVfY2xhc3NpYygpYCBmdW5jdGlvbi4gU2VlIFtoZXJlXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2d0aGVtZS5odG1sKSBmb3IgYSBsaXN0IG9mIG9wdGlvbnMuCgpgYGB7cn0KIG1ham9yX2dyb3Vwc19sb25nICU+JQogICBmaWx0ZXIoR2VuZGVyID09ICJBbGwiLAogICAgICAgICAgR3JvdXAgIT0gIlVuaXRlZCBTdGF0ZXMiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gUGVyY2VudCwgY29sb3IgPSBSYWNlX0V0aG5pY2l0eSkpICsKICBnZW9tX2xpbmUoIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KCBzaXplID0gMykgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwOCwyMDE4LCBieT0xKSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygyMDA4LDIwMjApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSg1LDMwLCBieSA9NSksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoNSwzMCkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKHJlcCggIiMwMDgzOTMiLCA1KSkpCgpgYGAKCk5vdyBsZXQncyBhZGQgc29tZSBsYWJlbHMuIFdlIGNhbiBhZGQgYSB0aXRsZSB1c2luZyB0aGUgYHRpdGxlYCBhcmd1bWVudCBhbmQgYSB5LWF4aXMgdGl0bGUgdXNpbmcgdGhlIGB5YCBhcmd1bWVudCBvZiB0aGUgYGxhYnMoKWAgZnVuY3Rpb24uCmBgYHtyfQogcGxvdCA8LW1ham9yX2dyb3Vwc19sb25nICU+JQogICBmaWx0ZXIoR2VuZGVyID09ICJBbGwiLAogICAgICAgICAgR3JvdXAgIT0gIlVuaXRlZCBTdGF0ZXMiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gUGVyY2VudCwgY29sb3IgPSBSYWNlX0V0aG5pY2l0eSkpICsKICBnZW9tX2xpbmUoIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KCBzaXplID0gMykgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwOCwyMDE4LCBieT0xKSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygyMDA4LDIwMjApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSg1LDMwLCBieSA9NSksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoNSwzMCkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnModGl0bGUgPSAiWU9VVEggRElTQ09OTkVDVElPTiBCWSBSQUNFIEFORCBFVEhOSUNJVFksIDIwMDggLSAyMDE3IiwKICAgICAgICAgICB5ID0gIllPVVRIIERJU0NPTk5FQ1RJT04gKCUpIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUodGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMwMDgzOTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMocmVwKCAiIzAwODM5MyIsIDUpKSkKCnBsb3QgPC0gZGlyZWN0bGFiZWxzOjpkaXJlY3QubGFiZWwocGxvdCwgbGlzdChkbC50cmFucyh4ID0geCsxLjIsIHkgPSB5ICswKSwgImxhc3QucG9pbnRzIikpCgpwbG90CmBgYAoKR2V0dGluZyBjbG9zZSEKCgpOb3cgd2UgbmVlZCB0byBhZGQgZmlndXJpbmUgaWNvbnMgdG8gdGhlIHBsb3QuICAKClRvIGFkZCB0aGUgZmlndXJpbmVzIHdlIGNhbiB1c2UgaWNvbnMgZnJvbSBmcmVlIHJlc291cmNlcyBsaWtlIFtmb250IGF3ZXNvbWVdKGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tLykuIFNlZSBbaGVyZV0oaHR0cHM6Ly9jb21tb25zLndpa2ltZWRpYS5vcmcvd2lraS9DYXRlZ29yeTpGb250X0F3ZXNvbWVfNF9pY29ucykgZm9yIGEgbGluayB0byBgc3ZnYCBvcHRpb25zLiBPciB3ZSBjb3VsZCBhbHNvIHRha2UgYSBzY3JlZW5zaG90IG9mIGp1c3QgdGhlIGZpZ3VyaW5lIGZyb20gdGhlIG9yaWdpbmFsIHBsb3QuIEhvd2V2ZXIsIGl0IGlzIHVzZWZ1bCB0byBrbm93IGhvdyB0byBjcmVhdGUgc2ltaWxhciBpY29ucyBpZiB3ZSBkaWRuJ3QgaGF2ZSB0aGUgb3JnaW5hbCBwbG90IHRvIHdvcmsgd2l0aC4gCgojIyMjIyBVc2luZyBmb250IGF3ZXNvbWU6CmBgYHtyLCBvdXQud2lkdGg9IjEwJSJ9CgpmYV9maWd1cmluZSA8LSBpbWFnZV9yZWFkKCJodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9jb21tb25zLzcvN2MvVXNlcl9mb250X2F3ZXNvbWUuc3ZnIikKCmZhX2ZpZ3VyaW5lCgpmYV9maWd1cmluZSA8LSBpbWFnZV9maWxsKGZhX2ZpZ3VyaW5lLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMwMDgzOTMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBwb2ludCA9ICIrODAwKzgwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZnV6eiA9IDApCmZhX2ZpZ3VyaW5lCmZhX2ZpZ3VyaW5lIDwtIGltYWdlX2ZpbGwoZmFfZmlndXJpbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHBvaW50ID0gIis4MDArMTAwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZnV6eiA9IDApCgpmYV9maWd1cmluZQpgYGAKCiMjIyMgVXNpbmcgYSBzY3JlZW5zaG90OgpgYGB7ciwgb3V0LndpZHRoPSAiMTAlIn0KCmZpZ3VyaW5lIDwtaW1hZ2VfcmVhZChoZXJlOjpoZXJlKCJpbWciLCAiZmlndXJpbmUucG5nIikpCmZpZ3VyaW5lCmBgYAoKTm93IHRvIGFkZCB0aGUgaW1hZ2Ugb2YgdGhlIGZpZ3VyaW5lIHRvIHRoZSBwbG90IHdlIGNhbiB1c2UgdGhlIGBkcmF3X2ltYWdlKClgIGZ1bmN0aW9uIG9mIHRoZSBgY293cGxvdGAgcGFja2FnZS4gV2Ugc2ltcGx5IG5lZWQgdG8gc3BlY2lmeSB0aGUgbmFtZSBvZiB0aGUgaW1hZ2UsIGFuZCB0aGVuIHdoZXJlIHdlIHdvdWxkIGxpa2UgaXQgdG8gZ28gYWNjb3JkaW5nIHRvIHRoZSB4LSBhbmQgeS1heGlzIGFuZCBmaW5hbHkgdGhlIHNjYWxlZCBzaXplIG9mIHRoZSBpbWFnZS4gVGhpcyBgc2NhbGVgIGFyZ3VtZW50IHRha2VzIGEgYml0IG9mIHRyaWFsIGFuZCBlcnJvci4gCgpIZXJlIHdlIHdpbGwgYWRkIGJvdGggaW1hZ2VzIG9mIHRoZSBmaWd1cmluZXMgdG8gYSBjb3VwbGUgb2YgZ3JvdXBzOgoKYGBge3J9CgpwbG90ICsKICBjb3dwbG90OjpkcmF3X2ltYWdlKGZpZ3VyaW5lLCB4ID0gMjAxNywgeSA9IDIzLjUsIHNjYWxlID0gNCkgKwogIGNvd3Bsb3Q6OmRyYXdfaW1hZ2UoZmFfZmlndXJpbmUsIHggPSAyMDE3LCB5ID0gMTcuNSwgc2NhbGUgPSAyKQoKCmBgYAoKTmljZSEKCk5vdyB3ZSBqdXN0IG5lZWQgdG8gYWRkIHRoaXMgZm9yIGFsbCBvZiB0aGUgZ3JvdXBzIGFuZCB3ZSBhbHNvIHdpbGwgd2FudCB0byByZXBsYWNlIG91ciBgTmF0aXZlIEFtZXJpY2FuYCBsYWJlbCB3aXRoIGEgdHdvIGxpbmUgdmVyc2lvbiBzbyB0aGF0IHdlIGxvb2sgYXMgc2ltaWxhciB0byB0aGUgcmVwb3J0IHBsb3QgYXMgcG9zc2libGUuCgojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKSG93IG1pZ2h0IHdlIGNoYW5nZSB0aGUgTmF0aXZlIEFtZXJpY2FuIGxhYmVsIHRvIGhhdmUgdHdvIGxpbmVzPyAoaGludDogdGhpbmsgYWJvdXQgaG93IHdlIHNlcGFyYXRlZCB0aGUgcm93cyBvZiBvdXIgdGFibGVzKQoKIyMjIwoKPGRldGFpbHM+IDxzdW1tYXJ5PkNsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLjwvc3VtbWFyeT4KCgpgYGB7cn0KcGxvdCA8LSBtYWpvcl9ncm91cHNfbG9uZyAlPiUKICAgZmlsdGVyKEdlbmRlciA9PSAiQWxsIiwKICAgICAgICAgIEdyb3VwICE9ICJVbml0ZWQgU3RhdGVzIikgJT4lCiAgIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9IHN0cl9yZXBsYWNlKHN0cmluZyA9IFJhY2VfRXRobmljaXR5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIk5hdGl2ZSBBbWVyaWNhbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJOYXRpdmVcbkFtZXJpY2FuIikpICAlPiUgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IFBlcmNlbnQsIGNvbG9yID0gUmFjZV9FdGhuaWNpdHkpKSArCiAgZ2VvbV9saW5lKCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludCggc2l6ZSA9IDMpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDgsMjAxOCwgYnk9MSksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwOCwyMDIwKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoNSwzMCwgYnkgPTUpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDUsMzApKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHRpdGxlID0gIllPVVRIIERJU0NPTk5FQ1RJT04gQlkgUkFDRSBBTkQgRVRITklDSVRZLCAyMDA4IC0gMjAxNyIsCiAgICAgICAgICAgeSA9ICJZT1VUSCBESVNDT05ORUNUSU9OICglKSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKHJlcCggIiMwMDgzOTMiLCA1KSkpKwogIGRyYXdfaW1hZ2UoZmlndXJpbmUsIHggPSAyMDE3LCB5ID0gMjMuNSwgc2NhbGUgPSA0KSArCiAgZHJhd19pbWFnZShmaWd1cmluZSwgeCA9IDIwMTcsIHkgPSAxNy41LCBzY2FsZSA9IDQpICsKICBkcmF3X2ltYWdlKGZpZ3VyaW5lLCB4ID0gMjAxNywgeSA9IDEzLjUsIHNjYWxlID0gNCkgKwogIGRyYXdfaW1hZ2UoZmlndXJpbmUsIHggPSAyMDE3LCB5ID0gOSwgc2NhbGUgPSA0KSArCiAgZHJhd19pbWFnZShmaWd1cmluZSwgeCA9IDIwMTcsIHkgPSA1LjUsIHNjYWxlID0gNCkKCnBsb3QgPC0gZGlyZWN0bGFiZWxzOjpkaXJlY3QubGFiZWwocGxvdCwgbGlzdChkbC50cmFucyh4ID0geCsxLjIsIHkgPSB5ICswKSwgImxhc3QucG9pbnRzIikpCmBgYAoKPC9kZXRhaWxzPgoKYGBge3J9CnBsb3QKYGBgCk5pY2UhIE91ciBwbG90IGxvb2tzIHZlcnkgc2ltaWxhciBzdHlsaXN0aWNhbGx5IHRvIHRoZSBwbG90IGluIHRoZSByZXBvcnQuIAoKV2UgY2FuIHNlZSBmcm9tIHRoaXMgcGxvdCB0aGF0IE5hdGl2ZSBBbWVyaWNhbnMgaGF2ZSBhIHZlcnkgaGlnaCByYXRlIG9mIHlvdXRoIGRpc2Nvbm5lY3Rpb24sIHdpdGggcm91Z2hseSBzdGlsbCBhIHF1YXJ0ZXIgb2YgdGhlIHBvcHVsYXRpb24gZXhwZXJpZW5jaW5nIHlvdXRoIGRpc2Nvbm5lY3Rpb24gaW4gdGhpcyBzdXJ2ZXkuIEFsdG91Z2ggc29tZSBncm91cHMgc2hvdyBhIGRvd253YXJkIHRyZW5kLCBsaWtlIHRoZSBMYXRpbnggZ3JvdXAsIHRoZSBsZXZlbCBoYXMgYmVlbiBmYWlybHkgc3RhYmxlIHNpbmNlIDIwMDgsIGFzIHdlIHNlZSB0aGF0IHRoZSBzbG9wZSBvZiBlYWNoIGxpbmUgaXMgZmFpcmx5IGZsYXQuIFdlIHdpbGwgaW52ZXN0aWdhdGUgdGhpcyBmdXJ0aGVyIGluIG91ciBhbmFseXNpcy4gCgojIyMgTWFqb3IgUmFjZSBhbmQgRXRobmljIEdyb3VwcyBhbmQgR2VuZGVyIFBsb3QKCk5vdyBsZXQncyBjcmVhdGUgYSBzaW1pbGFyIHBsb3QgZm9yIGZlbWFsZXMgYW5kIG1hbGVzLiBUbyBkbyB0aGlzIHdlIGNhbiBzaW1wbHkgdXNlIHRoZSBgZmFjZXRfd3JhcCgpYCBmdW5jdGlvbi4gV2UgbmVlZCB0byBzcGVjaWZ5IHdoYXQgdmFyaWFibGUgd2Ugd2FudCB0byBmYWNldCBieSwgaW4gdGhpcyBjYXNlIHRoZSBgR2VuZGVyYCB2YXJpYWJsZSwgYnkgdXNpbmcgdGhlIGB+YCBzeW1ib2wuIFdlIGFsc28gd2FudCB0byBzZXQgdGhlIGBzY2FsZXNgIGFyZ3VtZW50IHRvIGAiZnJlZSJgLCBzbyB0aGF0IHdlIGhhdmUgYSB5LWF4aXMgZm9yIGJvdGggdGhlIGZlbWFsZSBhbmQgbWFsZSBwbG90cy4gU2VlIHRoaXMgW2Nhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtY28yLWVtaXNzaW9ucy8jRmFjZXRlZF9wbG90cykgZm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgZmFjZXRpbmcgcGxvdHMuCgpXZSBhbHNvIGRvbnQgd2FudCB0byBwbG90IHRoZSBgIkFsbCJgIHZhbHVlcyBmb3IgdGhlIGBHZW5kZXJgIHZhcmlhYmxlIGFzIHdlIGhhdmUgYWxyZWFkeSBzaG93biB0aGF0IGluIHRoZSBwcmV2aW91cyBwbG90LCBzbyB3ZSBhZ2FpbiBleGNsdWRlIGl0LiAKCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpIb3cgZG8gd2UgbW9kaWZ5IHRoZSBjb2RlIHRvIG5vdCBpbmNsdWRlIHRoZSBgIkFsbCJgIHZhbHVlcyBmb3IgdGhlIGBHZW5kZXJgIHZhcmlhYmxlPwoKIyMjIwoKPGRldGFpbHM+IDxzdW1tYXJ5PkNsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLjwvc3VtbWFyeT4KCmBgYHtyfQpwbG90X2dlbmRlciA8LW1ham9yX2dyb3Vwc19sb25nICU+JQogICBmaWx0ZXIoUmFjZV9FdGhuaWNpdHkgIT0gIkFsbF9yYWNlcyIsCiAgICAgICAgICBHZW5kZXIgIT0gIkFsbCIpICU+JQogICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBzdHJfcmVwbGFjZShzdHJpbmcgPSBSYWNlX0V0aG5pY2l0eSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJOYXRpdmUgQW1lcmljYW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiTmF0aXZlXG5BbWVyaWNhbiIpLAogICAgICAgICAgICAgICAgICBHZW5kZXIgPSBzdHJfcmVwbGFjZShzdHJpbmcgPSBHZW5kZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiRmVtYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIkZFTUFMRSIpLAogICAgICAgICAgICAgICAgICBHZW5kZXIgPSBzdHJfcmVwbGFjZShzdHJpbmcgPSBHZW5kZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJNQUxFIikpICU+JQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCBjb2xvciA9IFJhY2VfRXRobmljaXR5KSkgKwogIGdlb21fbGluZShzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGZhY2V0X3dyYXAofkdlbmRlciwgc2NhbGVzID0gImZyZWUiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA4LDIwMTgsIGJ5PTEpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDIwMDgsMjAyMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDUsMzAsIGJ5ID01KSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyg1LDMxKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyh0aXRsZSA9ICJZT1VUSCBESVNDT05ORUNUSU9OIEJZIEdFTkRFUiBBTkQgUkFDSUFML0VUSE5JQyBHUk9VUCwgMjAwOCAtIDIwMTciLAogICAgICAgICAgIHkgPSAiWU9VVEggRElTQ09OTkVDVElPTiAoJSkiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLAogICAgICBzdHJpcC5iYWNrZ3JvdW5kID1lbGVtZW50X3JlY3QoZmlsbD0iIzAwMzY2MSIpLAogc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAnd2hpdGUnLCBmYWNlID0gImJvbGQiLCBzaXplID0gMTIpKSsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhyZXAoICIjMDA4MzkzIiwgNikpKQogCnBsb3RfZ2VuZGVyIDwtIGRpcmVjdC5sYWJlbChwbG90X2dlbmRlciwgbGlzdChkbC50cmFucyh4ID0geCswLjMsIHkgPSB5ICswKSwgImxhc3QucG9pbnRzIikpCgpgYGAKPC9kZXRhaWxzPgoKYGBge3J9CnBsb3RfZ2VuZGVyCgpgYGAKCgpJdCdzIGEgYml0IGRpZmZpY3VsdCB0byB0ZWxsIHRoZSBCbGFjayBmZW1hbGUgYW5kIExhdGlueCBmZW1hbGUgbGluZXMgYXBhcnQuIAoKTGV0J3MgdHJ5IGFkZGluZyBhbm90aGVyIGNvbG9yIGZvciBldmVyeSBvdGhlciBsaW5lLiBBZ2FpbiB3ZSB3aWxsIHVzZSB0aGUgYHNjYWxlX2NvbG9yX21hbnVhbCgpYCBmdW5jdGlvbiB0byBzcGVjaWZ5IHRoZSBjb2xvcnMgb2YgdGhlIGxpbmVzIGFuZCBwb2ludHMgb24gdGhlIHBsb3QuICAKCldlIHdpbGwgdXNlIGJsYWNrIGFzIHRoZSBvdGhlciBjb2xvci4gV2UgY2FuIHVzZSB0aGUgW2hleCB0cmlwbGV0XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XZWJfY29sb3JzP29sZGZvcm1hdD10cnVlKSBjb2RlIG9yIHdlIGNhbiB3cml0ZSBvdXQgdGhlIG5hbWUgb2YgdGhlIGNvbG9yLCBpbiB0aGlzIGNhc2Ugd2Ugd2lsbCB3cml0ZSBgImJsYWNrImAuIApUbyBzcGVjaWZpY2FsbHkgY29sb3IgZWFjaCBncm91cCBkaWZmZXJlbnRseSwgd2UgY2FuIHdyaXRlIHRoZSBjb2xvcnMgaW4gdGhlIGFscGhhYmV0aWNhbGx5IG9yZGVyIG9mIHRoZSBkaXN0aW5jdCB2YWx1ZXMgb2YgYFJhY2VfRXRobmljaXR5YC4gVGh1cyB0aGUgZmlyc3QgY29sb3IgbGlzdGVkIHdpbGwgYmUgdGhlIGNvbG9yIGZvciB0aGUgYEFzaWFuYCB2YWx1ZXMsIHdoaWxlIHRoZSBsYXN0IHdpbGwgYmUgdGhlIGNvbG9yIGZvciB0aGUgYFdoaXRlYCB2YWx1ZXMuCgoKYGBge3J9CnBsb3RfZ2VuZGVyIDwtIHBsb3RfZ2VuZGVyICArCiBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID1jKCIjMDA4MzkzIiwiYmxhY2siLCIjMDA4MzkzIiwgIiMwMDgzOTMiLCAiYmxhY2siKSkKYGBgCgoKIyMjIyB7LmV4cGxhaW5fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKQ2FuIHlvdSBleHBsYWluIHdoeSB3ZSBkaWRuJ3QgdXNlIGEgcGlwZSBpbiB0aGUgcHJldmlvdXMgY29kZSBjaHVuaz8KCiMjIyMKCmBgYHtyfQpwbG90X2dlbmRlcgpgYGAKVmVyeSBpbnRlcmVzdGluZyEgQnkgcGFyc2luZyB0aGUgZ3JvdXBzIGZ1cnRoZXIgaW50byBpbnRlcnNlY3Rpb25zIG9mIHJhY2lhbCBhbmQgZXRobmljIGdyb3VwcyB3aXRoIGdlbmRlciwgd2Ugc2VlIHRoYXQgdGhlcmUgYXJlIHNvbWUgdmVyeSBkcmFtYXRpYyBkaWZmZXJlbmNlcyBmb3IgdGhlIEJsYWNrIGFuZCBMYXRpbnggZ3JvdXBzLiBPbmUgcG9zdGl2ZSB0aGluZyB0aGF0IHdlIGNhbnMgc2VlLCBpcyB0aGF0IHRoZXJlIGhhcyBiZWVuIGEgc3RlZXAgZGVjbGluZSBpbiB5b3V0aCBkaXNjb25uZWN0aW9uIGZvciBMYXRpbnggZmVtYWxlcy4gVW5mb3J0dW5hdGVseSB0aGUgbGV2ZWwgb2YgZGlzY29ubmVjdGlvbiBmb3IgZmVtYWxlcyBpbiAyMDA4IHdhcyBxdWl0ZSBoaWdoLCBzbyBub3cgTGF0aW54IGZlbWFsZXMgaGF2ZSBzaW1pbGFyIHJhdGVzIHRvIExhdGlueCBtYWxlcy4gSW4gY29udHJhc3QsIHdlIHNlZSB0aGF0IEJsYWNrIG1hbGVzIGhhdmUgaGFkIGFuZCBjb250aW51ZSB0byBoYXZlIG11Y2ggaGlnaGVyIHJhdGVzIG9mIGRpc2Nvbm5lY3Rpb24gdGhhbiBCbGFjayBmZW1hbGVzLiBCb3RoIEJsYWNrIGZlbWFsZXMgYW5kIG1hbGVzIHNob3cgYW4gaW5jcmVhc2VkIHJhdGUgc2luY2UgMjAxNi4gTmF0aXZlIEFtZXJpY2FuIGZlbWFsZXMgYWxzbyBzaG93IGFuIGluY3JlYXNlZCByYXRlIHNpbmNlIDIwMTYuIAoKCiMjIyBTdWJncm91cCBwbG90cwoKSXQgaXMgY2xlYXIgZnJvbSB0aGUgcHJldmlvdXMgcGxvdCB0aGF0IG9ic2VydmluZyBtb3JlIHNwZWNpZmljIHN1Ymdyb3VwcyBpbiBvdXIgZGF0YSBjYW4gYmUgdmVyeSBpbmZvcm1hdGl2ZSEKClRodXMsIHdlIGFsc28gd2FudCB0byBtYWtlIHBsb3RzIG9mIHRoZSBBc2FpbiBhbmQgTGF0aW54IHN1Ymdyb3VwcywgdG8gc2VlIGlmIHRoZXJlIGFyZSBwYXJ0aWN1bGFyIGV0aG5pYyBncm91cHMgdGhhdCBoYXZlIGhpZ2hlciBsZXZlbHMgb2YgeW91dGggZGlzY29ubmVjdGlvbi4gSWYgc28sIHRoZXNlIGdyb3VwcyBtYXkgcGFydGljdWFybHkgYmVuZWZpdCBmb3IgcHJldmVudGlvbiBhbmQgcmVuZ2FnZW1lbnQgZWZmb3J0cy4KCldlIHdpbGwgYWxzbyBhdHRlbXB0IHRvIGNvbnRpbnVlIHRvIHBsb3QgdGhlIGdlbmRlcnMgc2VwYXJhdGVseSwgYXMgd2UgaGF2ZSBsZWFybmVkIHRoYXQgdGhlcmUgbWF5IGJlIGltcG9ydGFudCBnZW5kZXIgZ3JvdXAgZGlmZmVyZW5jZXMgYW1vbmcgdGhlIHJhY2lhbCBhbmQgZXRobmljIGdyb3Vwcy4gSG93ZXZlciwgdGhlIGRhdGEgaXMgaW5jb21wbGV0ZSBmb3Igc29tZSBvZiB0aGUgZXRobmljIGdyb3Vwcy4gUmVjYWxsIHRoYXQgd2UgYWxzbyBvbmx5IGhhdmUgdHdvIHllYXJzIG9mIGRhdGEgZm9yIGJvdGggb3VyIEFzaWFuIGFuZCBMYXRpbnggc3ViZ3JvdXAgZGF0YS4gRmlyc3Qgd2Ugd2lsbCBzdGFydCBieSBwbG90dGluZyBqdXN0IHRoZSBzdWJncm91cHMgb3ZlciB0aGUgdHdvIHllYXJzLgoKV2UgY2FuIGNvbnRpbnVlIHRvIG1ha2Ugb3VyIHBsb3RzIGxvb2sgbGlrZSB0aGV5IG1hdGNoIHRoZSByZXBvcnQgYnkgdXNpbmcgYSBjb2xvciBwYWxldHRlIGJhc2VkIG9mZiB0aGUgY29sb3IgdXNlZCBpbiB0aGUgcmVwb3J0LiBXZSBjYW4gdXNlIHRoZSBgY29sb3JSYW1wUGFsZXR0ZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGdyRGV2aWNlc2AgcGFja2FnZSwgd2hpY2ggaXMgbG9hZGVkIGF1dG9tYXRpY2FsbHkgaW4gYW4gUlN0dWRpbyBzZXNzaW9uLiBXZSBjYW4gc3BlY2lmeSB0aGF0IHdlIHdhbnQgdGhlIGNvbG9ycyB0byByYW5nZSBmcm9tIGdyYXkgdG8gdGhlIGNvbG9yIHRoYXQgd2UgaGF2ZSBiZWVuIHVzaW5nLgoKVGhlbiB3ZSBqdXN0IG5lZWQgdG8gc3BlY2lmeSBob3cgbWFueSBjb2xvcnMgd2Ugd2FudCBpbiBvdXIgZ3JhZGllbnQgd2hlbiB3ZSBjaG9vc2UgdG8gdXNlIHRoZSBjb2xvciBwYWxsZXR0ZS4gU2F5IHdlIHdhbnRlZCAzIGNvbG9ycywgd2UganVzdCBuZWVkIHRvIHR5cGUgYGN1c3RvbV9wYWwoMylgIHRvIGdldCBhIGxpc3Qgb2YgMyBjb2xvcnMgd2l0aGluIHRoZSBwYWxldHRlLiBUaHVzIHdlIHdpbGwgaGF2ZSBncmF5LCB0aGUgdGVhbCBjb2xvciB3ZSBoYXZlIGJlZW4gdXNpbmcsIGFuZCBhIHNoYWRlIGluIGJldHdlZW4uCgpgYGB7cn0KY3VzdG9tX3BhbCA8LSBjb2xvclJhbXBQYWxldHRlKGMoImdyYXkiLCAiIzAwODM5MyIpKQpjdXN0b21fcGFsIDwtY3VzdG9tX3BhbCg0KQpjdXN0b21fcGFsIDwtYygiIzAwODM5MyIsIiNCRUJFQkUiKQpgYGAKCkhlcmUgd2UgY2FuIHNlZSB0aGUgW2hleCB0cmlwbGV0XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XZWJfY29sb3JzP29sZGZvcm1hdD10cnVlKSBjb2RlcyBmb3IgZ3JheSBhbmQgdGhlIHNoYWRlIGluIGJldHdlZW4uCgoKCk9LLCBub3cgbGV0J3Mgc3RhcnQgd2l0aCB0aGUgQXNpYW4gc3ViZ3JvdXBzLiBTaW5jZSB3ZSBvbmx5IGhhdmUgdHdvIHRpbWUgcG9pbnRzIG9mIGRhdGEgZm9yIGVhY2ggZ3JvdXAsIHdlIHdpbGwgY3JlYXRlIGEgYmFyIGdyYXBoIHRoaXMgdGltZSB3aGVyZSB0aGUgdHdvIHllYXJzIGFyZSBkaXNwbGF5ZWQgbmV4dCB0byBlYWNoIG90aGVyIGZvciBlYWNoIHllYXIuIFRodXMsIHdlIHdhbnQgdGhlIGBZZWFyYCB2YXJpYWJsZSB0byBiZSBhIGRpc2NyZXRlIHZhcmlhYmxlLiBUbyBlbnN1cmUgdGhhdCBpdCBpcyBpbnRlcnByZXRlZCBhcyBhIGRpc2NyZXRlIHZhcmlhYmxlLCB3ZSBuZWVkIHRvIGNvbnZlcnQgaXQgdG8gYmUgYSBjaGFyYWN0ZXIgdHlwZSB2YXJpYWJsZSByYXRoZXIgdGhhbiBudW1lcmljIHVzaW5nIHRoZSBiYXNlIGBhcy5jaGFyYWN0ZXIoKWAgZnVuY3Rpb24uIAoKCkZpcnN0LCB3ZSB3YW50IHRvIGZpbHRlciBmb3IgdGhlIHJvd3Mgd2hlcmUgdGhlIGBHZW5kZXJgIHZhcmlhYmxlIHZhbHVlcyBhcmUgYEFsbGAsIHdlIGFsc28gZG8gbm90IHdhbnQgdG8gaW5jbHVkZSB0aGUgZGF0YSBmb3IgdGhlIGF2ZXJhZ2Ugb2YgYWxsIHJhY2VzLiBXZSBhbHNvIAoKYGBge3J9CmFzaWFuX3N1Ymdyb3VwcyAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJBbGwiKSAlPiUKICBmaWx0ZXIoUmFjZV9FdGhuaWNpdHkgIT0gIkFsbF9yYWNlcyIpICU+JQogIG11dGF0ZShZZWFyID0gYXMuY2hhcmFjdGVyKFllYXIpKQpgYGAKCk5vdyB0aGF0IHdlIGhhdmUgd3JhbmdsZWQgdGhlIGRhdGEgd2UgY2FuIG1ha2Ugb3VyIHBsb3QuIFRvIG1ha2UgYSBiYXIgcGxvdCB0aGVyZSBhZSB0d28gbWFueSBgZ2dwbG90MmAgZnVuY3Rpb25zLCAgYGdlb21fY29sKClgIGFuZCBgZ2VvbV9iYXIoKWAuIFRoZSBgZ2VvbV9jb2woKWAgZnVuY3Rpb24gcGxvdHMgdGhlIGFjdHVhbCB2YWx1ZXMgb2YgdGhlIGRhdGEsIHdoaWxlIHRoZSBgZ2VvbV9iYXIoKWBmdW5jdGlvbiBwbG90cyBjb3VudHMgKGhvd2V2ZXIgeW91IGNhbiBvdmVycmlkZSB0aGlzIHdpdGggdGhlIGBzdGF0ID0gaWRlbnRpdHlgIGFyZ3VtZW50KS4gV2UgYXJlIGludGVyZXN0ZWQgaW4gcGxvdHRpbmcgdGhlIGFjdHVhbCB2YWx1ZXMsIHNvIHdlIHdpbGwgdXNlIHRoZSBgZ29lbV9jb2woKWAgZnVuY3Rpb24uCgpUaGlzIHRpbWUgd2Ugd2lsbCBzcGVjaWZ5IHRoYXQgdGhlIGBZZWFyYCB2YXJpYWJsZSBiZSB1c2VkIHRvIHNwZWNpZnkgdGhlIGZpbGwgY29sb3Igb2YgdGhlIGJhcnMgb2YgdGhlIGJhciBwbG90IGJ5IHVzaW5nIGBhZXMoZmlsbCA9IFllYXIpYC4KCldlIGFsc28gbmVlZCB0byBpbmRpY2F0ZSBob3cgdGhlIGJhcnMgc2hvdWxkIGJlIHBsb3R0ZWQgYmFzZWQgb24gdGhlIGBwb3NpdGlvbmAgYXJndW1lbnQuCgpUaGUgb3B0aW9ucyBmb3IgdGhlIGBwb3NpdGlvbmAgYXJndW1lbnQgYXJlOgotIHN0YWNrIC0gdGhlIHllYXJzIHdvdWxkIGJlIGRpc3BsYXllZCBvbiB0b3Agb2Ygb25lIGFub3RoZXIgKHRoaXMgaXMgZGVmYXVsdCkgICAKLSBkb2RnZSAtIHRoZSB5ZWFycyB3b3VsZCBiZSBkaXNwbGF5ZWQgbmV4dCB0byBvbmUgYW5vdGhlciB3aXRoIG5vIHNwYWNlIGluIGJldHdlZW4gICAKLSBkb2RnZTIgLSB0aGUgeWVhcnMgd291bGQgYmUgZGlzcGxheWVkIG5leHQgdG8gb25lIGFub3RoZXIgd2l0aCBhIHNwYWNlIGluIGJldHdlZW4gICAKLSBmaWxsICAtIHRoZSB5ZWFycyB3b3VsZCBiZSBkaXNwbGF5ZWQgb24gdG9wIG9mIG9uZSBvdGhlciwgd2hlcmUgdGhlIGhlaWdodHMgb2YgZWFjaCBjb2xvciB3b3VsZCBzaG93IHRoZSByZWxhdGl2ZSBwcm9wb3J0aW9ucyBmb3IgZWFjaCB5ZWFyIGFkZGluZyB1cCB0byAxLCB0aHVzIGVhY2ggYmFyIHdvdWxkIGhhdmUgdGhlIHNhbWUgaGVpZ2h0ICAgICAKCldlIHdpbGwgdXNlIHRoZSBkb2RnZSBvcHRpb24uCgpGb3IgdGhlIGNvbG9ycywgd2UgY2FuIHRyeSBvdXQgdmFyaW91cyBudW1iZXJzIG9mIHNoYWRlcyBmb3IgdGhlIHBhbGV0dGUgdGlsbCB3ZSBnZXQgc2hhZGVzIHRoYXQgd2UgbGlrZS4gSW4gdGhpcyBjYXNlLCAyIHNoYWRlcyBvdXQgb2YgYSBncmFkaWVudCBvZiA0IHNoYWRlcyBmcm9tIGdyYXkgdG8gdGVhbCBsb29rcyBuaWNlLAoKYGBge3J9ICAKYXNpYW5fc3ViZ3JvdXBzICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIkFsbCIpICU+JQogIGZpbHRlcihSYWNlX0V0aG5pY2l0eSAhPSAiQWxsX3JhY2VzIikgJT4lCiAgbXV0YXRlKFllYXIgPSBhcy5jaGFyYWN0ZXIoWWVhcikpICU+JQpnZ3Bsb3QoYWVzKHggPSBSYWNlX0V0aG5pY2l0eSwgeSA9IFBlcmNlbnQpKSArCiAgZ2VvbV9jb2woYWVzKGZpbGwgPSBZZWFyKSwgcG9zaXRpb24gPSAiZG9kZ2UiKSsKICBsYWJzKHRpdGxlID0gIllPVVRIIERJU0NPTk5FQ1RJT04gQlkgQVNJQU4gU1VCR1JPVVAsIDIwMTctMjAxOCIsCiAgICAgICAgICAgeSA9ICJZT1VUSCBESVNDT05ORUNUSU9OICglKSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjdXN0b21fcGFsKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgpgYGAKCk9LLCB0aGlzIGxvb2tzIHByZXR0eSBuaWNlISBIb3dldmVyLCB3ZSBjYW4gaW1wcm92ZSB0aGlzIGEgYml0LgoKQmVmb3JlIHdlIGRvIHNvLCBsZXQncyBjcmVhdGUgYSB0aGVtZSBmb3Igb3VyIGZ1dHVyZSBzaW1pbGFyIGdncGxvdHMgbGlrZSBzbzoKCmBgYHtyfQpiYXJfdGhlbWUgPC1mdW5jdGlvbigpIHsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkKICB9CmBgYAoKTm93IHdlIHNpbXBseSBuZWVkIHRvIHR5cGUgYGJhcl90aGVtZSgpYCBpbnN0ZWFkIHRvIGFjaGlldmUgdGhlIHNhbWUgc3R5bGUgZm9yIG91ciBwbG90LgoKSXQgd291bGQgYmUgbmljZSBpZiBmb3Igc3ViZ3JvdXBzIHRoYXQgb25seSBoYXZlIG9uZSB5ZWFyIG9mIGRhdGEsIGlmIHRoZSBjb2x1bW4gdGhhdCB3YXMgZGlzcGxheWVkIHdhcyBzdGlsbCB0aGUgc2FtZSB3aWR0aCBhcyB0aGUgdGhhdCBvZiB0aGUgb3RoZXIgZ3JvdXBzLiBUbyBkbyB0aGlzIHdlIG5lZWQgYSByb3cgd2l0aCBhbiBgTkFgIHZhbHVlIGZvciB0aGUgeWVhciB0aGF0IGlzIG1pc3NpbmcuIE9uZSB3YXkgdG8gYWNjb21wbGlzaCB0aGlzIGlzIHRvIHVzZSB0aGUgYHBpdm90X3dpZGVyKClgIGFuZCBgcGl2b3RfbG9uZ2VyKClgIGZ1bmN0aW9ucyB0byB3aWRlbiB0aGUgZGF0YSBiYXNlZCBvbiB0aGUgYFllYXJgIHZhcmlhYmxlIGFuZCB0aGUgY29sbGFwc2UgdGhlIGRhdGEgYmFzZWQgb24gdGhlIGBZZWFyYCB2YXJpYWJsZS4gQnkgd2lkZW5pbmcgb3VyIGRhdGEsIHdlIGNyZWF0ZSB0aGUgYE5BYCB2YWx1ZXMgd2Ugd2FudDsgaG93ZXZlciB3ZSBuZWVkIHRvIGNvbGxhcHNlIG91ciBkYXRhIGJhY2sgdG8gdGhlIGxvbmcgZm9ybWF0IHNvIHRoYXQgd2UgY2FuIGVhc2lseSB1c2UgYGdncGxvdDJgIHRvIHBsb3QgdGhlIHllYXIgYXMgdGhlIGZpbGwgaW4gb3VyIGJhciBwbG90LgoKTm90ZSB0aGF0IHdlIG5vIGxvbmdlciBuZWVkIHRvIGNoYW5nZSB0aGUgdHlwZSBvZiB0aGUgYFllYXJgIHZhcmlhYmxlLCBhcyBpdCBpcyBhdXRvbWF0aWNhbGx5IGNvbnZlcnRlZCB0byB0eXBlIGNoYXJhY3Rlci4KCmBgYHtyfQphc2lhbl9zdWJncm91cHMgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiQWxsIikgJT4lCiAgZmlsdGVyKFJhY2VfRXRobmljaXR5ICE9ICJBbGxfcmFjZXMiKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1Hcm91cCkgJT4lCnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZZWFyLCB2YWx1ZXNfZnJvbSA9IFBlcmNlbnQpCmBgYAoKR3JlYXQhIE5vdyB3ZSBoYXZlIGBOQWAgdmFsdWVzLiBOb3cgd2UganVzdCB0byBnZXQgdGhlIGRhdGEgYmFjayBpbnRvIGxvbmcgZm9ybWF0OgoKYGBge3J9CmFzaWFuX3N1Ymdyb3VwcyAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJBbGwiKSAlPiUKICBmaWx0ZXIoUmFjZV9FdGhuaWNpdHkgIT0gIkFsbF9yYWNlcyIpICU+JQogIGRwbHlyOjpzZWxlY3QoLUdyb3VwKSAlPiUKcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFllYXIsIHZhbHVlc19mcm9tID0gUGVyY2VudCkgJT4lCnBpdm90X2xvbmdlcihjb2xzID0gLWMoUmFjZV9FdGhuaWNpdHksIEdlbmRlciksIApuYW1lc190byA9IlllYXIiICwgCnZhbHVlc190bz0iUGVyY2VudCIpCmBgYAoKR3JlYXQsIG5vdyBsZXQncyBzZWUgaG93IHRoaXMgbG9va3MgaW4gdGhlIHBsb3QuCgpgYGB7cn0gIAphc2lhbl9zdWJncm91cHMgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiQWxsIikgJT4lCiAgZmlsdGVyKFJhY2VfRXRobmljaXR5ICE9ICJBbGxfcmFjZXMiKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1Hcm91cCkgJT4lCnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZZWFyLCB2YWx1ZXNfZnJvbSA9IFBlcmNlbnQpICU+JQpwaXZvdF9sb25nZXIoY29scyA9IC1jKFJhY2VfRXRobmljaXR5LCBHZW5kZXIpLCAKbmFtZXNfdG8gPSJZZWFyIiAsIAp2YWx1ZXNfdG89IlBlcmNlbnQiKSAlPiUKZ2dwbG90KGFlcyh4ID0gUmFjZV9FdGhuaWNpdHksIHkgPSBQZXJjZW50KSkgKwogIGdlb21fY29sKGFlcyhmaWxsID0gWWVhciksIHBvc2l0aW9uID0gImRvZGdlIikrCiAgbGFicyh0aXRsZSA9ICJZT1VUSCBESVNDT05ORUNUSU9OIEJZIEFTSUFOIFNVQkdST1VQLCAyMDE3LTIwMTgiLAogICAgICAgICAgIHkgPSAiWU9VVEggRElTQ09OTkVDVElPTiAoJSkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY3VzdG9tX3BhbCkgKwogIGJhcl90aGVtZSgpCgpgYGAKCkdyZWF0ISB0aGF0IGlzIGxvb2tpbmcgYmV0dGVyISBIb3dldmVyLCBjdXJyZW50bHkgdGhlIHN1Ymdyb3VwcyBhcmUgcGxvdHRlZCBvbiB0aGUgeC1heGlzIGJ5IGFscGhhYmV0aWNhbGx5IG9yZGVyIGFuZCB3ZSB3YW50IHRvIGluc3RlYWQgb3JkZXIgdGhlIHN1Ymdyb3VwcyBiYXNlZCBvbiB0aGUgcGVyY2VudGFnZSBvZiB5b3V0aCBkaXNjb25uZWN0aW9uLiBXZSBjYW4gdXNlIHRoZSBgZm9yY2F0c2AgcGFja2FnZSB0byBkbyB0aGlzLiAKClRoZSBgZmN0X3Jlb3JkZXIoKWAgZnVuY3Rpb24gY2FuIGJlIHVzZWQgdG8gb3JkZXIgdGhlIGBSYWNlX0V0aG5pY2l0eWAgdmFyaWFibGUgYmFzZWQgb24gdGhlIGF2ZXJhZ2Ugb2YgdGhlIGBQZXJjZW50YCB2YXJpYWJsZSBmb3IgdGhlIHR3byB5ZWFycywgd2hpbGUgdGhlIGBmY3RfcmVsZXZlbCgpYCBmdW5jdGlvbiBjYW4gYmUgdXNlZCB0byBtYWtlIHRoZSBgQXNpYW5gIGxldmVsIGFwcGVhciBmaXJzdCBmb3IgY29tcGFyaXNvbiBzYWtlLiBJbXBvcmFudGx5LCB3ZSBuZWVkIHRvIGRvIHRoaXMgYmVmb3JlIHdlIHJlc2hhcGUgdGhlIGRhdGEsIGJlY2F1c2Ugc3ViZ3JvdXBzIHdpdGggYE5BYCB2YWx1ZXMgd2lsbCBiZSBwbGFjZWQgYXQgdGhlIGVuZC4KCgpgYGB7cn0KYXNpYW5fc3ViZ3JvdXBzICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIkFsbCIpICU+JQogIGZpbHRlcihSYWNlX0V0aG5pY2l0eSAhPSAiQWxsX3JhY2VzIikgJT4lCiAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gZmN0X3Jlb3JkZXIoUmFjZV9FdGhuaWNpdHksIFBlcmNlbnQpKSAlPiUKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBmY3RfcmVsZXZlbChSYWNlX0V0aG5pY2l0eSwgIkFzaWFuIikpICU+JSAKICBzZWxlY3QoLUdyb3VwKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWWVhciwgdmFsdWVzX2Zyb20gPSBQZXJjZW50KSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKFJhY2VfRXRobmljaXR5LCBHZW5kZXIpLCAKICBuYW1lc190byA9IlllYXIiICwgCiAgdmFsdWVzX3RvPSJQZXJjZW50IiklPiUKICBnZ3Bsb3QoYWVzKHggPSBSYWNlX0V0aG5pY2l0eSwgeSA9IFBlcmNlbnQpKSArCiAgICBnZW9tX2NvbChhZXMoZmlsbCA9IFllYXIpLCBwb3NpdGlvbiA9ICJkb2RnZSIpKwogICAgbGFicyh0aXRsZSA9ICJZT1VUSCBESVNDT05ORUNUSU9OIEJZIEFTSUFOIFNVQkdST1VQIiwKICAgICAgc3VidGl0bGUgPSAiT1JERVJFRCBCWSBBVkVSQUdFIERJU0NPTk5FQ1RJT04gTEVWRUwgT0YgMjAxNyAmIDIwMTgiLAogICAgICAgICAgICAgeSA9ICJZT1VUSCBESVNDT05ORUNUSU9OICglKSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjdXN0b21fcGFsKSArICAgIGJhcl90aGVtZSgpCgpgYGAKVGhpcyBpcyBsb29raW5nIHZlcnkgZ29vZCEgTm93LCBsZXQncyBtYWtlIGEgZ2FwIGJldHdlZW4gdGhlIEFzaWFuIGF2ZXJhZ2UgZ3JvdXAgYW5kIHRoZSBzdWJncm91cHMgdG8gbW9yZSBlYXNpbHkgZGlmZmVyZW50aWF0ZSBiZXR3ZWVuIHRoZSB0d28gYW5kIGxldCdzIHVzZSB0aGF0IHNwYWNlIHRvIGFkZCB0aGUgZmlndXJlIGxlZ2VuZCB0byB0aGUgcGxvdCBpdHNlbGYuCgoKVG8gZmlyc3QgbWFrZSBhIGdhcCwgd2UgY2FuIHVzZSB0aGUgYHNjYWxlX3hfZGlzY3JldGUoKWAgZnVuY3Rpb24uIFdlIG5lZWQgdG8gd3JpdGUgdGhlIG5hbWUgb2YgdGhlIGxldmVscyBvZiB0aGUgYFJhY2VfRXRobmljaXR5YCB2YXJpYWJsZSBhbmQgcGxhY2UgYSBibGFuayBpbiBiZXR3ZWVuIHRoZSBgQXNpYW5gIGxldmVsIGFuZCB0aGUgc3Vic2VxdWVudCBsZXZlbHMuIFdlIGNhbiB1c2UgdGhlIGBsZXZlbHMoKWAgZnVuY3Rpb24gdG8gbWFrZSB0aGlzIG1vcmUgcmVwcm9kdWNpYmxlIGFuZCB0byBhdm9pZCBtaXN0YWtlcyBpbnN0ZWFkIG9mIGFjdHVhbGx5IHdyaXRpbmcgb3V0IGVhY2ggb2YgdGhlIGxldmVscyBieSBoYW5kLgoKSGVyZSB5b3UgY2FuIHNlZSBhbGwgdGhlIGxldmVsczoKCmBgYHtyfQphc2lhbl9zdWJncm91cHMgJT4lCiAgZHBseXI6OnNlbGVjdCgtR3JvdXApICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIkFsbCIpICU+JQogIGZpbHRlcihSYWNlX0V0aG5pY2l0eSAhPSAiQWxsX3JhY2VzIikgJT4lCiAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gIGZjdF9yZW9yZGVyKFJhY2VfRXRobmljaXR5LCBQZXJjZW50KSkgJT4lIAogIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9IGZjdF9yZWxldmVsKFJhY2VfRXRobmljaXR5LCAiQXNpYW4iKSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFllYXIsIHZhbHVlc19mcm9tID0gUGVyY2VudCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtYyhSYWNlX0V0aG5pY2l0eSwgR2VuZGVyKSwgCiAgbmFtZXNfdG8gPSAiWWVhciIgLCAKICB2YWx1ZXNfdG8gPSAiUGVyY2VudCIpJT4lCiAgcHVsbChSYWNlX0V0aG5pY2l0eSkgJT4lCiAgbGV2ZWxzKCkKYGBgClRvIHNpbXBsaWZ5IG91ciBjb2RlIHdlIHdpbGwgc2F2ZSBvdXIgd3JhbmdsZWQgZGF0YSBhcyBhIHRpYmJsZSBjYWxsZWQgYGFzYWluX2Zvcl9wbG90YC4KCgpTbyB3ZSB3b3VsZCBsaWtlIG91ciB4LWF4aXMgdG8gYmUgbGlrZSB0aGlzOgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpzY2FsZV94X2Rpc2NyZXRlKAogIGxpbWl0cyA9IGMoIkFzaWFuIiwKICAgICAgICAgICAgICJCbGFuayIsCiAgICAgICAgICAgICAiTkVYVF9ibGFuayIsCiAgICAgICAgICAgICBsZXZlbHMocHVsbChhc2lhbl9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpWzI6MTBdKSwKICBsYWJlbHMgPSBjKCJCbGFuayIgPSAiIiwKICAgICAgICAgICAgICJORVhUX2JsYW5rIj0gIiIpKQpgYGAKClRoZSBgbGV2ZWxzKHB1bGwoYXNpYW5fZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsyOjEwXSlgIGNvZGUgZ2V0cyBhbGwgOSBvdGhlciBsZXZlbHMgYnV0IHRoZSBgQXNpYW5gIGxldmVsIG9mIHRoZSBgUmFjZV9FdGhuaWNpdHlgIHZhcmlhYmxlLiBUaGUgYGxhYmVsc2AgYXJndW1lbnQgc3BlY2lmaWVzIHdoYXQgdGhlIHgtYXhpcyBzaG91bGQgc2F5IGZvciB0aGUgc3BhY2VzIGluIGJldHdlZW4uIFdlIHdvdWxkIGxpa2UgdGhlbSB0byBzYXkgbm90aGluZywgc28gd2UgdXNlIG5vdGhpbmcgd2l0aGluIHF1b3RlcyBgIiJgIGFzIHRoZSBsYWJlbC4gCgpXZSBjYW4gYWxzbyB1c2UgdGhpcyBhcyBhbiBvcHBvcnR1bml0eSB0byBjaGFuZ2UgdGhlIGxhYmVsIG9uIHRoZSBwbG90IGZvciB0aGUgYEFzaWFuYCBsZXZlbCBvZiB0aGUgYFJhY2VfRXRobmljaXR5YCB2YXJpYWJsZSB0byBiZSBgIkFzaWFuIGF2Zy4iYC4gV2UgZG9udCB3YW4ndCB0byBjaGFuZ2UgdGhlIG90aGVyIHN1Ymdyb3VwIGxldmVsIGxhYmVscyBzbyB3ZSB3aWxsIG5vdCBsaXN0IGFueXRoaW5nLgoKV2UgY2FuIG1ha2UgdGhpcyBtb3JlIHJlcHJlZHVjaWJsZSBieSB1c2luZyB0aGUgYGxlbmd0aCgpYCBmdW5jdGlvbiBpc3RlYWQgb2YgdGhlIG51bWJlciAxMCBhbmQgcmVwbGFjaW5nIGBBc2lhbmAgd2l0aCB0aGUgZmlyc3QgbGV2ZWw6CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpzY2FsZV94X2Rpc2NyZXRlKAogIGxpbWl0cyA9IGMobGV2ZWxzKHB1bGwoYXNpYW5fZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsxXSwKICAgICAgICAgICAgICJCbGFuayIsCiAgICAgICAgICAgICAiTkVYVF9ibGFuayIsCiAgICAgICAgICAgICBsZXZlbHMocHVsbChhc2lhbl9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpWzI6CiAgICAgICAgICAgICBsZW5ndGgobGV2ZWxzKHB1bGwoYXNpYW5fZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKSldKSwKICBsYWJlbHMgPSBjKCJBc2lhbiIgPSAiQXNpYW4gQXZnLiIsCiAgICAgICAgICAgICAiQmxhbmsiID0gIiIsCiAgICAgICAgICAgICAiTkVYVF9ibGFuayI9ICIiKSkKYGBgCgoKClRoZW4gd2UgY2FuIHVzZSBgbGVnZW5kLmp1c3RpZmljYXRpb25gIGFuZCBgbGVnZW5kLnBvc2l0aW9uYCBvZiB0aGUgYHRoZW1lKClgIGZ1bmN0aW9uIHRvIG1vdmUgb3VyIGxlZ2VuZCB0byB0aGUgcGxvdCBhcmVhLiAKCkFjY29yZGluZyB0byB0aGUgZG9jdW1lbnRhYXRpb24gZm9yIHRoZSBgdGhlbWUoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlLCB0aGUgYGxlZ2VuZC5qdXN0aWZpY2F0aW9uYCBhcmd1bWVudCBzcGVjaWZpZXMgdGhlOgoKPiBhbmNob3IgcG9pbnQgZm9yIHBvc2l0aW9uaW5nIGxlZ2VuZCBpbnNpZGUgcGxvdCAoImNlbnRlciIgb3IgdHdvLWVsZW1lbnQgbnVtZXJpYyB2ZWN0b3IpIG9yIHRoZSBqdXN0aWZpY2F0aW9uIGFjY29yZGluZyB0byB0aGUgcGxvdCBhcmVhIHdoZW4gcG9zaXRpb25lZCBvdXRzaWRlIHRoZSBwbG90CgpCeSBzZXR0aW5nIHRoZSBtYXBwaW5nIGZvciB0aGUgcG9zaXRpb25pbmcgYW5kIGp1c3RpZmFjYXRpb24gYXMgYGMoMC4xMiwwLjEpYCB3ZSBzcGVjaWZ5IHRoYXQgd2Ugd2FudCB0aGUgbGVnZW5kIHRvIGJlIDEyIHBlcmNlbnQgb2YgdGhlIHBsb3QgYXJlYSBmcm9tIHRoZSB5IC1heGlzIGFuZCAxMCBwZXJjZW50IG9mIHRoZSBwbG90IGFyZWEgZnJvbSB0aGUgeC1heGlzLgoKCmBgYHtyfQphc2lhbl9mb3JfcGxvdCA8LWFzaWFuX3N1Ymdyb3VwcyAlPiUKICBkcGx5cjo6c2VsZWN0KC1Hcm91cCkgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiQWxsIikgJT4lCiAgZmlsdGVyKFJhY2VfRXRobmljaXR5ICE9ICJBbGxfcmFjZXMiKSAlPiUKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSAgZmN0X3Jlb3JkZXIoUmFjZV9FdGhuaWNpdHksIFBlcmNlbnQpKSAlPiUgCiAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gZmN0X3JlbGV2ZWwoUmFjZV9FdGhuaWNpdHksICJBc2lhbiIpKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWWVhciwgdmFsdWVzX2Zyb20gPSBQZXJjZW50KSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKFJhY2VfRXRobmljaXR5LCBHZW5kZXIpLCAKICBuYW1lc190byA9ICJZZWFyIiAsIAogIHZhbHVlc190byA9ICJQZXJjZW50IikKCmFzaWFuX3N1Ymdyb3VwX3Bsb3QgPC1hc2lhbl9mb3JfcGxvdCAlPiUKZ2dwbG90KGFlcyh4ID0gUmFjZV9FdGhuaWNpdHksIHkgPSBQZXJjZW50LCBmaWxsID0gWWVhcikpICsKIGdlb21fY29sKGFlcyhmaWxsID0gWWVhciksIHBvc2l0aW9uID0gImRvZGdlIikrCiAgbGFicyh0aXRsZSA9ICJZT1VUSCBESVNDT05ORUNUSU9OIEJZIEFTSUFOIFNVQkdST1VQIEFORCBZRUFSIiwKICAgICAgIHN1YnRpdGxlID0gIk9SREVSRUQgQlkgQVZFUkFHRSBESVNDT05ORUNUSU9OIExFVkVMIE9GIDIwMTcgJiAyMDE4IiwKICAgICAgIHkgPSAiWU9VVEggRElTQ09OTkVDVElPTiAoJSkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY3VzdG9tX3BhbCkgKwogIHNjYWxlX3hfZGlzY3JldGUoCiAgbGltaXRzID0gYyhsZXZlbHMocHVsbChhc2lhbl9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpWzFdLAogICAgICAgICAgICAgIkJsYW5rIiwKICAgICAgICAgICAgICJORVhUX2JsYW5rIiwKICAgICAgICAgICAgIGxldmVscyhwdWxsKGFzaWFuX2Zvcl9wbG90LFJhY2VfRXRobmljaXR5KSlbMjoKICAgICAgICAgICAgIGxlbmd0aChsZXZlbHMocHVsbChhc2lhbl9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpKV0pLAogIGxhYmVscyA9IGMoIkFzaWFuIiA9ICJBc2lhbiBBdmcuIiwKICAgICAgICAgICAgICJCbGFuayIgPSAiIiwKICAgICAgICAgICAgICJORVhUX2JsYW5rIj0gIiIpKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLG1heChwdWxsKGFzaWFuX3N1Ymdyb3VwcyxQZXJjZW50KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkpKSsKICBiYXJfdGhlbWUoKSsKICAjdGhpcyBhZGQgdGhlIGxlZ2VuZCB0byB0aGUgcGxvdCBhcmVhIToKICAgICAgICB0aGVtZShsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMC4xMiwwLjEpLAogICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4xMiwuMSkpCgphc2lhbl9zdWJncm91cF9wbG90CmBgYAoKTmljZSEgQnV0LCB0aGlzIGlzIHN0aWxsIG1pc3Npbmcgc29tZXRoaW5nLiBQZXJoYXBzIGlmIHdlIGFkZCBsaW5lcyB0aGF0IHNob3cgdGhlIGF2ZXJhZ2UgZGlzc2NvbmVjdGlvbiByYXRlIGZvciB0aGUgVVMgYW5kIGZvciBBc2lhbnMgaW4gZ2VuZXJhbCwgdGhlbiBpdCB3aWxsIG1ha2UgaXQgZWFzaWVyIHRvIHNlZSBkaWZmZXJlbmNlcyBpbiBvdXIgcGxvdC4KCkluIHRoZSBwcmV2aW91cyBjb2RlIHdlIHNhdmVkIG91ciBwbG90IHRvIGEgb25qZWN0IGNhbGxlZCBgYXNpYW5fc3ViZ3JvdXBfcGxvdGAuCgpXZSBjYW4gbW9kaWZ5IGl0IGJ5IGFkZGluZyBsYXllcnMgdG8gYWRkIHRoZSBsaW5lcyB0aGF0IHdlIHdhbnQuCgpGaXJzdCB3ZSB3YW50IHRvIGNyZWF0ZSBvYmplY3RzIGZvciB0aGUgVVMgYXZlcmFnZSBhbmQgYXNpYW4gYXZlcmFnZSBkaXNjb25uZWN0aW9uIHJhdGVzLiAKCmBgYHtyLCBldmFsID0gRkFMU0V9CmFzaWFuX3RvdGFsIDwtIGFzaWFuX3N1Ymdyb3VwcyU+JQogICBmaWx0ZXIoWWVhciA9PSAyMDE3LAogICAgICAgIEdlbmRlciA9PSAiQWxsIiwKUmFjZV9FdGhuaWNpdHkgPT0gIkFzaWFuIikgJT4lCiAgbXV0YXRlKFllYXIgPSBhcy5jaGFyYWN0ZXIoWWVhcikpCiAgcHVsbChQZXJjZW50KQoKVVNfdG90YWwgPC0gYXNpYW5fc3ViZ3JvdXBzJT4lCiAgIGZpbHRlcihZZWFyID09IDIwMTcsCiAgICAgICAgR2VuZGVyID09ICJBbGwiLApSYWNlX0V0aG5pY2l0eSA9PSAiQWxsX3JhY2VzIikgJT4lCiAgcHVsbChQZXJjZW50KQoKbGF0aW54X3RvdGFsIDwtIGxhdGlueF9zdWJncm91cHMgJT4lCiAgZmlsdGVyKFllYXIgPT0gMjAxNykgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiQWxsIiwKIFJhY2VfRXRobmljaXR5ID09ICJMYXRpbngiKSAlPiUKICBwdWxsKFBlcmNlbnQpCgpgYGAKCkZpcnN0IHdlIHdhbnQgdG8gY3JlYXRlIHRpYmJsZXMgZm9yIHRoZSBVUyBBc2lhbiBhdmVyYWdlIGRpc2Nvbm5lY3Rpb24gcmF0ZXMuIFdlIHdhbnQgdG8gYWRkIGxhYmVscyB0byBlYWNoIG9mIHRoZXNlLiBXZSBjYW4gdXNlIHRoZSBgcGFyc2UgPSBUUlVFYCBhcmd1bWVudCBsYXRlciB3aXRoIHRoZSBgZ2VvbV90ZXh0KClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZSB0byBtYWtlIHRoZXNlIGxhYmVscyBhcHBlYXIgYXMgYm9sZCBmb250IGFzIGl0IHdpbGwgYmUgZXZhbHVhdGVkIGFzIGFuIGV4cHJlc3Npb24gaXN0ZWFkIG9mIGEgc2ltcGxlIGNoYXJhY3RlciBzdHJpbmcuCgpgYGB7cn0KCiAgYXNpYW5fdG90YWwgPC0gYXNpYW5fc3ViZ3JvdXBzJT4lCiAgIGZpbHRlcihZZWFyID09IDIwMTcsCiAgICAgICAgR2VuZGVyID09ICJBbGwiLApSYWNlX0V0aG5pY2l0eSA9PSAiQXNpYW4iKSAlPiUKICBtdXRhdGUoWWVhciA9IGFzLmNoYXJhY3RlcihZZWFyKSkgJT4lCiBtdXRhdGUobGFiZWwgPSBjKCdib2xkKCJBU0lBTiAyMDE3IEFWRyBSQVRFIiknKSkKClVTX3RvdGFsIDwtIGFzaWFuX3N1Ymdyb3VwcyU+JQogICBmaWx0ZXIoWWVhciA9PSAyMDE3LAogICAgICAgIEdlbmRlciA9PSAiQWxsIiwKUmFjZV9FdGhuaWNpdHkgPT0gIkFsbF9yYWNlcyIpICU+JQogIG11dGF0ZShZZWFyID0gYXMuY2hhcmFjdGVyKFllYXIpKSAlPiUKIG11dGF0ZShsYWJlbCA9IGMoJ2JvbGQoIlVTIDIwMTcgQVZHIFJBVEUiKScpKQoKYXNpYW5fdG90YWwKVVNfdG90YWwKYGBgCgpOb3cgd2UgY2FuIHVzZSB0aGVzZSB0byBjcmVhdGUgbGFiZWxzIGFnYWluIHdpdGggdGhlIGBnZW9tX3RleHQoKWAgZnVuY3Rpb24gYW5kIGxpbmVzIHdpdGggdGhlIGBnZW9tX2hsaW5lKClgIGZ1bmN0aW9uIG9uIG91ciBwbG90LiAKClRoZSBgZ2VvbV90ZXh0KClgIGZ1bmN0aW9uIHJlcXVpcmVzIHRoYXQgdGhlIHggYW5kIHkgYXhpcyBsb2NhdGlvbiBmb3IgdGhlIHRleHQgYmUgc3BlY2lmaWVkLCBhbmQgd2Ugd2FudCB0aGlzIHRvIGJlIGxvY2F0ZWQgbmVhciB0aGUgYWN0dWFsIHBlcmNlbnQgZGlzc29uY2F0aW9uIHJhdGUsIHRodXMgd2UgdXNlIHRoZSBgUGVyY2VudCArLjVgIHRvIGdyYWIgdGhlIGBQZXJjZW50YCB2YWx1ZSBmcm9tIGBhc2lhbl90b3RhbGAgYW5kIGFkZCAwLjUgdG8gaXQgdG8gYmUgc2xpZ2h0bHkgYWJvdmUgd2hlcmUgdGhlIGxpbmUgd2lsbCBiZS4gCgpUaGUgYGdlb21faGxpbmUoKWAgZnVuY3Rpb24gcmVxdWlyZXMsIGp1c3QgdGhlIHlpbnRlcmNlcHQgYXMgdGhpcyBmdW5jdGlvbiBhbHdheXMgY3JlYXRlcyBhIGhvcml6b250YWwgbGluZS4gVGhlIGBsaW5ldHlwZWAgYXJndW1lbnQgc3BlY2lmaWVzIHdoYXQgc3R5bGUgb2YgbGluZSB3ZSB3b3VsZCBsaWtlLiBTZWUgW2hlcmVdKGh0dHA6Ly9zYXBlLmluZi51c2kuY2gvcXVpY2stcmVmZXJlbmNlL2dncGxvdDIvbGluZXR5cGUpIGZvciBhIGxpc3Qgb2Ygb3B0aW9ucy4KCmBgYHtyfQphc2lhbl9zdWJncm91cF9wbG90PC0gYXNpYW5fc3ViZ3JvdXBfcGxvdCsgCiAgZ2VvbV90ZXh0KGRhdGEgPSBhc2lhbl90b3RhbCwKICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gMi41LCB5ID0gUGVyY2VudCArLjcsIGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgIHBhcnNlID0gVFJVRSwKICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwgCiAgICAgICAgICAgIHNpemUgPSA0KSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IHB1bGwoYXNpYW5fdG90YWwsIFBlcmNlbnQpKSwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBVU190b3RhbCwKICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gMi41LCB5ID0gUGVyY2VudCArLjcsIGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgIHBhcnNlID0gVFJVRSwKICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwgCiAgICAgICAgICAgIHNpemUgPSA0KSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IHB1bGwoVVNfdG90YWwsIFBlcmNlbnQpKSwgbGluZXR5cGUgPSAzKQoKYXNpYW5fc3ViZ3JvdXBfcGxvdApgYGAKQXdlc29tZSEgTm93IGl0IGlzIG11Y2ggZWFzaWVyIHRvIHRlbGwgaG93IHRoZSBkaXNjb25uZWN0aW9uIHJhdGVzIGZvciB2YXJpb3VzIHN1Ymdyb3VwcyBjb21wYXJlIHRvIHRoZSBuYXRpb25hbCBhdmVyYWdlIGFuZCB0aGUgQXNpYW4gYXZlcmFnZS4gRnJvbSBvdXIgcGxvdCwgd2UgY2FuIHNlZSB0aGF0IHRoZSBbSG1vbmddKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0htb25nX3Blb3BsZSkgYW5kIENhbWJvZGlhbiBzdWJncm91cCByYXRlcyBhcmUgdmVyeSBoaWdoLiBJZiB3ZSBvbmx5IGhhZCB0aGUgcGxvdCBvZiBtYWpvciByYWNpYWwgYW5kIGV0aG5pYyBncm91cHMgdG8gcmVseSBvbiwgd2UgbWlnaHQgbm90IHJlYWxpemUgdGhhdCB0aGVzZSB0d28gZ3JvdXBzIGhhdmUgc3VjaCBoaWdoIHJhdGVzLiAKCmBgYHtyLCBldmFsID0gRkFMU0V9CiAgICBhbm5vdGF0ZSgidGV4dCIsIGxhYmVsID0gJ2JvbGQoIkFTSUFOIDIwMTcgQVZHIFJBVEUiKScsCiAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsIAogICAgICAgICAgIHNpemUgPSAzLjcsCiAgICAgICAgICAgeCA9IDIuNSwKICAgICAgICAgICB5ID0gYXNpYW5fdG90YWwrLjUsCiAgICAgICAgICAgcGFyc2UgPSBUUlVFKSArCiAgICBhbm5vdGF0ZSgidGV4dCIsIGxhYmVsID0gJ2JvbGQoIlVTIDIwMTcgQVZHIFJBVEUiKScsCiAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsIAogICAgICAgICAgIHNpemUgPSA0LAogICAgICAgICAgIHggPSAyLjUsCiAgICAgICAgICAgeSA9IFVTX3RvdGFsICsuNSwgCiAgICAgICAgICAgcGFyc2UgPSBUUlVFKSsKZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IGFzaWFuX3RvdGFsKSwgbGluZXR5cGUgPSAyKSArCmdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBVU190b3RhbCksIGxpbmV0eXBlID0gMykKCmBgYAoKTmljZSEgVGhpcyBzaG93cyB0aGUgaW1wb3J0YW5jZSBvZiBhZGRpbmcgc21hbGwgZGV0YWlscyBzdWNoIGFzIHRoZSBVUyBhbmQgQXNpYW4gcmF0ZSBsaW5lcy4gVGhpcyBoZWxwcyBwcm92aWRlIGEgc2ltcGxlIHlldCBudWFuY2VkIHBpY3R1cmUgb2Ygd2hhdCBpcyBnb2luZyBvbi4gCgpGcm9tIHRoZSBhYm92ZSBwbG90LCBpdCBiZWNvbWVzIHJlYWRpbHkgYXBwYXJlbnQgdGhhdCB0aGUgSG1vbmcgYW5kIENhbWJvZGlhbiBzdWJncm91cHMgaGF2ZSBtdWNoIGhpZ2hlciBkaXNjb25uZWN0aW9uIHJhdGVzIHRoYW4gdGhlIG90aGVyIEFzaWFuIHN1Ymdyb3VwcywgYXMgd2VsbCBhcyBhbGwgcmFjZXMvZXRobmljaXRpZXMgaW4gdGhlIFVTIGNvbWJpbmVkLiAKCgpXZSBjYW4gY29uZmlybSB0aGlzIGJ5IHJldmlzaXRpbmcgdGhlIHRhYmxlcy4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNTAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgImFzaWFuXzIwMTdfb3ZlcnZpZXcucG5nIikpCgpgYGAKCgoKYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgImFzaWFuXzIwMThfb3ZlcnZpZXcucG5nIikpCgpgYGAKCkZyb20gdGhlIDIwMTggdGFibGUsIHdlIGNhbiBjYWx1Y3VsYXRlIHRoYXQgdGhlIEhtb25nIGdyb3VwIHJlcHJlc2VudGVkIGByIHJvdW5kKCg1MzAwKjEwMCkvKDIzMzAwKzIxODAwKzkwMDArMTUzMDArMjA4MDArNTMwMCs0MjAwKSlgJSBhbmQgdGhlIENhbWJvZGlhbiBzdWJncm91cCByZXByZXNlbnRlZCBgciByb3VuZCgoNDIwMCoxMDApLygyMzMwMCsyMTgwMCs5MDAwKzE1MzAwKzIwODAwKzUzMDArNDIwMCkpYCUgIHJlc3BlY3RpdmVseSBvZiBhbGwgQXNpYW4gZGlzY29ubmVjdGVkIHlvdXRoIGluIDIwMTcuIAoKCklmIHdlIHdhbnRlZCB0byBtYWtlIGEgc2ltaWxhciBwbG90IGJ1dCB3aXRob3V0IHRoZSBzdWJncm91cHMgdGhhdCBhcmUgbWlzc2luZyBhIHllYXIgd2UgY291bGQgZG8gaXQgbGlrZSBzbywgYnkgYWRkaW5nIHRoZSBgZHJvcF9uYSgpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlIHRvIHJlbW92ZSByb3dzIHdpdGggYE5BYCB2YWx1ZXMgd2hlbiB0aGUgZGF0YSAgaXMgaW4gd2lkZSAgZm9ybSBhbmQgdGhlbiB1c2luZyB0aGUgYGZjdF9kcm9wKClgIGZ1bmN0aW9uIG9mIHRoZSBgZm9yY2F0c2AgcGFja2FnZSB0byByZW1vdmUgdGhlIGxldmVscyBvZiB0aGUgYFJhY2VfRXRobmljaXR5YCB2YXJpYWJsZSB0aGF0IG5vIGxvbmdlciBoYXZlIHJvd3MgaW4gdGhlIGRhdGEuIAoKYGBge3J9CmFzaWFuX2Zvcl9wbG90IDwtYXNpYW5fc3ViZ3JvdXBzICU+JQogIGRwbHlyOjpzZWxlY3QoLUdyb3VwKSAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJBbGwiKSAlPiUKICBmaWx0ZXIoUmFjZV9FdGhuaWNpdHkgIT0gIkFsbF9yYWNlcyIpICU+JQogIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9ICBmY3RfcmVvcmRlcihSYWNlX0V0aG5pY2l0eSwgUGVyY2VudCkpICU+JSAKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBmY3RfcmVsZXZlbChSYWNlX0V0aG5pY2l0eSwgIkFzaWFuIikpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZZWFyLCB2YWx1ZXNfZnJvbSA9IFBlcmNlbnQpICU+JQogIHRpZHlyOjpkcm9wX25hKCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtYyhSYWNlX0V0aG5pY2l0eSwgR2VuZGVyKSwgCiAgbmFtZXNfdG8gPSAiWWVhciIgLCAKICB2YWx1ZXNfdG8gPSAiUGVyY2VudCIpJT4lCiAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gZmN0X2Ryb3AoUmFjZV9FdGhuaWNpdHkpKQoKYXNpYW5fc3ViZ3JvdXBfcGxvdF9zaW1wIDwtYXNpYW5fZm9yX3Bsb3QgJT4lCmdncGxvdChhZXMoeCA9IFJhY2VfRXRobmljaXR5LCB5ID0gUGVyY2VudCwgZmlsbCA9IFllYXIpKSArCiBnZW9tX2NvbChhZXMoZmlsbCA9IFllYXIpLCBwb3NpdGlvbiA9ICJkb2RnZSIpKwogIGxhYnModGl0bGUgPSAiWU9VVEggRElTQ09OTkVDVElPTiBCWSBBU0lBTiBTVUJHUk9VUCBBTkQgWUVBUiIsCiAgICAgICBzdWJ0aXRsZSA9ICJPUkRFUkVEIEJZIEFWRVJBR0UgRElTQ09OTkVDVElPTiBMRVZFTCBPRiAyMDE3ICYgMjAxOCIsCiAgICAgICB5ID0gIllPVVRIIERJU0NPTk5FQ1RJT04gKCUpIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9wYWwpICsKICBzY2FsZV94X2Rpc2NyZXRlKAogIGxpbWl0cyA9IGMobGV2ZWxzKHB1bGwoYXNpYW5fZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsxXSwKICAgICAgICAgICAgICJCbGFuayIsCiAgICAgICAgICAgICAiTkVYVF9ibGFuayIsCiAgICAgICAgICAgICBsZXZlbHMocHVsbChhc2lhbl9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpWzI6CiAgICAgICAgICAgICBsZW5ndGgobGV2ZWxzKHB1bGwoYXNpYW5fZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKSldKSwKICBsYWJlbHMgPSBjKCJBc2lhbiIgPSAiQXNpYW4gQXZnLiIsCiAgICAgICAgICAgICAiQmxhbmsiID0gIiIsCiAgICAgICAgICAgICAiTkVYVF9ibGFuayI9ICIiKSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCxtYXgocHVsbChhc2lhbl9zdWJncm91cHMsUGVyY2VudCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKSkrCiAgYmFyX3RoZW1lKCkrCiAgI3RoaXMgYWRkIHRoZSBsZWdlbmQgdG8gdGhlIHBsb3QgYXJlYSE6CiAgdGhlbWUobGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAuMTYsMC4wMSksbGVnZW5kLnBvc2l0aW9uID0gYygwLjE2LC4wMSkpKyAgZ2VvbV90ZXh0KGRhdGEgPSBhc2lhbl90b3RhbCwKICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gMi41LCB5ID0gUGVyY2VudCArLjcsIGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgIHBhcnNlID0gVFJVRSwKICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwgCiAgICAgICAgICAgIHNpemUgPSA0KSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IHB1bGwoYXNpYW5fdG90YWwsIFBlcmNlbnQpKSwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBVU190b3RhbCwKICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gMi41LCB5ID0gUGVyY2VudCArLjcsIGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgIHBhcnNlID0gVFJVRSwKICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwgCiAgICAgICAgICAgIHNpemUgPSA0KSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IHB1bGwoVVNfdG90YWwsIFBlcmNlbnQpKSwgbGluZXR5cGUgPSAzKQpgYGAKCgpgYGB7cn0KCmFzaWFuX3N1Ymdyb3VwX3Bsb3Rfc2ltcApgYGAKCk5vdyBsZXQncyBkbyB0aGUgc2FtZSBmb3IgdGhlIExhdGlueCBzdWJncm91cHMuCgojIyMgTGF0aW54IFN1Ymdyb3VwcwoKRmlyc3QgbGV0J3MgbWFrZSB0aGUgc21hbGwgdGliYmxlIG9mIHRoZSAyMDE3IExhdGlueCBhdmVyYWdlIHJhdGUgbGlrZSB3ZSBkaWQgZm9yIHRoZSBVUyBhbmQgZm9yIEFzaWFucyB0byBjcmVhdGUgdGhlIGxpbmVzIGFuZCB0ZXh0IG9uIG91ciBwbG90LgoKYGBge3J9CmxhdGlueF90b3RhbCA8LSBsYXRpbnhfc3ViZ3JvdXBzJT4lCiAgIGZpbHRlcihZZWFyID09IDIwMTcsCiAgICAgICAgR2VuZGVyID09ICJBbGwiLApSYWNlX0V0aG5pY2l0eSA9PSAiTGF0aW54IikgJT4lCiAgbXV0YXRlKFllYXIgPSBhcy5jaGFyYWN0ZXIoWWVhcikpICU+JQogbXV0YXRlKGxhYmVsID0gYygnYm9sZCgiTEFUSU5YIDIwMTcgQVZHIFJBVEUiKScpKQpgYGAKCgpgYGB7cn0KbGF0aW54X2Zvcl9wbG90IDwtbGF0aW54X3N1Ymdyb3VwcyAlPiUKICBkcGx5cjo6c2VsZWN0KC1Hcm91cCkgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiQWxsIikgJT4lCiAgZmlsdGVyKFJhY2VfRXRobmljaXR5ICE9ICJBbGxfcmFjZXMiKSAlPiUKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBzdHJfcmVwbGFjZSgKICAgICAgICAgICAgICAgICBzdHJpbmcgPSBSYWNlX0V0aG5pY2l0eSwgCiAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIlB1ZXJ0byBSaWNhbiwgRG9taW5pY2FuLCBDdWJhbiIsCiAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIlB1ZXJ0byBSaWNhbixcbkRvbWluaWNhbixcbkN1YmFuIikpICU+JQogIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9ICBmY3RfcmVvcmRlcihSYWNlX0V0aG5pY2l0eSwgUGVyY2VudCkpICU+JSAKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBmY3RfcmVsZXZlbChSYWNlX0V0aG5pY2l0eSwgIkxhdGlueCIpKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWWVhciwgdmFsdWVzX2Zyb20gPSBQZXJjZW50KSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKFJhY2VfRXRobmljaXR5LCBHZW5kZXIpLCAKICBuYW1lc190byA9ICJZZWFyIiAsIAogIHZhbHVlc190byA9ICJQZXJjZW50IikKCmxhdGlueF9zdWJncm91cF9wbG90PC1sYXRpbnhfZm9yX3Bsb3QgJT4lCmdncGxvdChhZXMoeCA9IFJhY2VfRXRobmljaXR5LCB5ID0gUGVyY2VudCwgZmlsbCA9IFllYXIpKSArCiBnZW9tX2NvbChhZXMoZmlsbCA9IFllYXIpLCBwb3NpdGlvbiA9ICJkb2RnZSIpKwogIGxhYnModGl0bGUgPSAiWU9VVEggRElTQ09OTkVDVElPTiBCWSBMQVRJTlggU1VCR1JPVVAgQU5EIFlFQVIiLAogICAgc3VidGl0bGUgPSAiT1JERVJFRCBCWSBBVkVSQUdFIERJU0NPTk5FQ1RJT04gTEVWRUwgT0YgMjAxNyAmIDIwMTgiLAogICAgICAgICAgIHkgPSAiWU9VVEggRElTQ09OTkVDVElPTiAoJSkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY3VzdG9tX3BhbCkgKwogIHNjYWxlX3hfZGlzY3JldGUoCiAgbGltaXRzID0gYyhsZXZlbHMocHVsbChsYXRpbnhfZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsxXSwKICAgICAgICAgICAgICJCbGFuayIsCiAgICAgICAgICAgICAiTkVYVF9ibGFuayIsCiAgICAgICAgICAgICBsZXZlbHMocHVsbChsYXRpbnhfZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsyOgogICAgICAgICAgICAgbGVuZ3RoKGxldmVscyhwdWxsKGxhdGlueF9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpKV0pLAogIGxhYmVscyA9IGMoIkxhdGlueCIgPSAiTGF0aW54IEF2Zy4iLAogICAgICAgICAgICAgIkJsYW5rIiA9ICIiLAogICAgICAgICAgICAgIk5FWFRfYmxhbmsiPSAiIikpKwogIGJhcl90aGVtZSgpKwogICN0aGlzIGFkZCB0aGUgbGVnZW5kIHRvIHRoZSBwbG90IGFyZWEhOgogIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLjIzLDAuMSksbGVnZW5kLnBvc2l0aW9uID0gYygwLjIzLC4xKSkrCiAgZ2VvbV90ZXh0KGRhdGEgPSBsYXRpbnhfdG90YWwsCiAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IDMsIHkgPSBQZXJjZW50ICsuNywgbGFiZWwgPSBsYWJlbCksCiAgICAgICAgICAgcGFyc2UgPSBUUlVFLAogICAgICAgICAgIGNvbG9yID0gIiMwMDgzOTMiLCAKICAgICAgICAgICAgc2l6ZSA9IDQpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gcHVsbChsYXRpbnhfdG90YWwsIFBlcmNlbnQpKSwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBVU190b3RhbCwKICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gMywgeSA9IFBlcmNlbnQgKy43LCBsYWJlbCA9IGxhYmVsKSwKICAgICAgICAgICBwYXJzZSA9IFRSVUUsCiAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsIAogICAgICAgICAgICBzaXplID0gNCkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBwdWxsKFVTX3RvdGFsLCBQZXJjZW50KSksIGxpbmV0eXBlID0gMykKYGBgCgpgYGB7cn0KbGF0aW54X3N1Ymdyb3VwX3Bsb3QKCmBgYAoKCgpgYGB7cn0KbGF0aW54X2Zvcl9wbG90IDwtbGF0aW54X3N1Ymdyb3VwcyAlPiUKICBkcGx5cjo6c2VsZWN0KC1Hcm91cCkgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiQWxsIikgJT4lCiAgZmlsdGVyKFJhY2VfRXRobmljaXR5ICE9ICJBbGxfcmFjZXMiKSAlPiUKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBzdHJfcmVwbGFjZSgKICAgICAgICAgICAgICAgICBzdHJpbmcgPSBSYWNlX0V0aG5pY2l0eSwgCiAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIlB1ZXJ0byBSaWNhbiwgRG9taW5pY2FuLCBDdWJhbiIsCiAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIlB1ZXJ0byBSaWNhbixcbkRvbWluaWNhbixcbkN1YmFuIikpICU+JQogIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9ICBmY3RfcmVvcmRlcihSYWNlX0V0aG5pY2l0eSwgUGVyY2VudCkpICU+JSAKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBmY3RfcmVsZXZlbChSYWNlX0V0aG5pY2l0eSwgIkxhdGlueCIpKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWWVhciwgdmFsdWVzX2Zyb20gPSBQZXJjZW50KSAlPiUKICB0aWR5cjo6ZHJvcF9uYSgpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLWMoUmFjZV9FdGhuaWNpdHksIEdlbmRlciksIAogIG5hbWVzX3RvID0gIlllYXIiICwgCiAgdmFsdWVzX3RvID0gIlBlcmNlbnQiKSU+JQogIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9IGZjdF9kcm9wKFJhY2VfRXRobmljaXR5KSkKCmxhdGlueF9zdWJncm91cF9wbG90X3NpbXAgPC1sYXRpbnhfZm9yX3Bsb3QgJT4lCmdncGxvdChhZXMoeCA9IFJhY2VfRXRobmljaXR5LCB5ID0gUGVyY2VudCwgZmlsbCA9IFllYXIpKSArCiBnZW9tX2NvbChhZXMoZmlsbCA9IFllYXIpLCBwb3NpdGlvbiA9ICJkb2RnZSIpKwogIGxhYnModGl0bGUgPSAiWU9VVEggRElTQ09OTkVDVElPTiBCWSBMQVRJTlggU1VCR1JPVVAgQU5EIFlFQVIiLAogICAgc3VidGl0bGUgPSAiT1JERVJFRCBCWSBBVkVSQUdFIERJU0NPTk5FQ1RJT04gTEVWRUwgT0YgMjAxNyAmIDIwMTgiLAogICAgICAgICAgIHkgPSAiWU9VVEggRElTQ09OTkVDVElPTiAoJSkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY3VzdG9tX3BhbCkgKwogIHNjYWxlX3hfZGlzY3JldGUoCiAgbGltaXRzID0gYyhsZXZlbHMocHVsbChsYXRpbnhfZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsxXSwKICAgICAgICAgICAgICJCbGFuayIsCiAgICAgICAgICAgICAiTkVYVF9ibGFuayIsCiAgICAgICAgICAgICBsZXZlbHMocHVsbChsYXRpbnhfZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsyOgogICAgICAgICAgICAgbGVuZ3RoKGxldmVscyhwdWxsKGxhdGlueF9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpKV0pLAogIGxhYmVscyA9IGMoIkxhdGlueCIgPSAiTGF0aW54IEF2Zy4iLAogICAgICAgICAgICAgIkJsYW5rIiA9ICIiLAogICAgICAgICAgICAgIk5FWFRfYmxhbmsiPSAiIikpKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsbWF4KHB1bGwobGF0aW54X3N1Ymdyb3VwcyxQZXJjZW50KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkpKSsKICBiYXJfdGhlbWUoKSsKICAjdGhpcyBhZGQgdGhlIGxlZ2VuZCB0byB0aGUgcGxvdCBhcmVhIToKICB0aGVtZShsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMC4yMywwLjAxKSxsZWdlbmQucG9zaXRpb24gPSBjKDAuMjMsLjAxKSkrCiAgZ2VvbV90ZXh0KGRhdGEgPSBsYXRpbnhfdG90YWwsCiAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IDMsIHkgPSBQZXJjZW50ICsuNywgbGFiZWwgPSBsYWJlbCksCiAgICAgICAgICAgcGFyc2UgPSBUUlVFLAogICAgICAgICAgIGNvbG9yID0gIiMwMDgzOTMiLCAKICAgICAgICAgICAgc2l6ZSA9IDQpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gcHVsbChsYXRpbnhfdG90YWwsIFBlcmNlbnQpKSwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBVU190b3RhbCwKICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gMywgeSA9IFBlcmNlbnQgKy43LCBsYWJlbCA9IGxhYmVsKSwKICAgICAgICAgICBwYXJzZSA9IFRSVUUsCiAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsIAogICAgICAgICAgICBzaXplID0gNCkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBwdWxsKFVTX3RvdGFsLCBQZXJjZW50KSksIGxpbmV0eXBlID0gMykKCgpgYGAKCgpgYGB7cn0KCmxhdGlueF9zdWJncm91cF9wbG90X3NpbXAKYGBgCgoKCgojIyMgU3ViZ3JvdXAgYnkgR2VuZGVyIFBsb3RzCgpOb3cgdGhhdCB3ZSBoYXZlIG1hZGUgcGxvdHMgZm9yIHRoZSBldGhuaWMgc3ViZ3JvdXBzLCBsZXQncyB0YWtlIGEgbG9vayBhdCBnZW5kZXIgZGlmZmVyZW5jZXMgYW1vbmcgdGhlIHN1Ymdyb3Vwcy4KCmBgYHtyfQphc2lhbl90b3RhbApVU190b3RhbAphc2lhbl90b3RhbFsiR2VuZGVyIl08LWMoIk1hbGUiKQpVU190b3RhbFsiR2VuZGVyIl08LWMoIk1hbGUiKQpgYGAKCmBgYHtyfQojIGN1c3RvbV9wYWwgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJuYXZ5IiwgIndoaXRlIikpCiMgY3VzdG9tX3BhbCgzKQojIAojIGN1c3RvbV9wYWwgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJsaWdodGJsdWUiLCAid2hpdGUiKSkKIyBjdXN0b21fcGFsKDMpCgoKZ2VuZGVyX3BhbCA8LSBjKCJnb2xkIiwgIiMwMDM2NjEiKQoKZ2VuZGVyX3BhbCA8LSBjb2xvclJhbXBQYWxldHRlKGMoImdyYXkiLCAiIzAwMzY2MSIpKQoKZ2VuZGVyX3BhbCA8LSBjKCIjMDAzNjYxIiwiZ3JheSIpCmBgYAoKCmBgYHtyfQphc2lhbl9mb3JfcGxvdCA8LWFzaWFuX3N1Ymdyb3VwcyAlPiUKICBmaWx0ZXIoR2VuZGVyICE9ICJBbGwiKSAlPiUKICBmaWx0ZXIoUmFjZV9FdGhuaWNpdHkgIT0gIkFsbF9yYWNlcyIpICU+JQogICAgYWRkX3JvdyhSYWNlX0V0aG5pY2l0eSA9ICJIbW9uZyIsCiAgICAgICAgICBHZW5kZXIgPSAiRmVtYWxlIiwKICAgICAgICAgIFllYXIgPSAyMDE3LAogICAgICAgICAgUGVyY2VudCA9IE5BKSAlPiUKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSAgZmN0X3Jlb3JkZXIoUmFjZV9FdGhuaWNpdHksIFBlcmNlbnQpKSAlPiUgCiAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gZmN0X3JlbGV2ZWwoUmFjZV9FdGhuaWNpdHksICJBc2lhbiIpKSAlPiUKICBzZWxlY3QoLUdyb3VwKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWWVhciwgdmFsdWVzX2Zyb20gPSBQZXJjZW50KSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKFJhY2VfRXRobmljaXR5LCBHZW5kZXIpLCAKICBuYW1lc190byA9ICJZZWFyIiAsIAogIHZhbHVlc190byA9ICJQZXJjZW50IikKCgphc2lhbl9nZW5kZXJfc3ViZ3JvdXBfcGxvdDwtYXNpYW5fZm9yX3Bsb3QgJT4lCmdncGxvdChhZXMoeCA9IFJhY2VfRXRobmljaXR5LCB5ID0gUGVyY2VudCkpICsKZ2VvbV9jb2woYWVzKGZpbGwgPSBHZW5kZXIpLCBwb3NpdGlvbiA9ICJkb2RnZSIpKwogIGxhYnModGl0bGUgPSAiWU9VVEggRElTQ09OTkVDVElPTiBCWSBBU0lBTiBTVUJHUk9VUCBBTkQgR0VOREVSIiwKICAgIHN1YnRpdGxlID0gIk9SREVSRUQgQlkgQVZFUkFHRSBESVNDT05ORUNUSU9OIExFVkVMIE9GIEZFTUFMRVMgJiBNQUxFUyAoMjAxNy0yMDE4KSIsCiAgICAgICAgICAgeSA9ICJZT1VUSCBESVNDT05ORUNUSU9OICglKSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPShnZW5kZXJfcGFsKSkgKwogIHNjYWxlX3hfZGlzY3JldGUoCiAgbGltaXRzID0gYyhsZXZlbHMocHVsbChhc2lhbl9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpWzFdLAogICAgICAgICAgICAgIkJsYW5rIiwKICAgICAgICAgICAgICJOZXh0X0JsYW5rIiwKICAgICAgICAgICAgIGxldmVscyhwdWxsKGFzaWFuX2Zvcl9wbG90LFJhY2VfRXRobmljaXR5KSlbMjoKICAgICAgICAgICAgIGxlbmd0aChsZXZlbHMocHVsbChhc2lhbl9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpKV0pLAogIGxhYmVscyA9IGMoIkFzaWFuIiA9ICJBc2lhbiBBdmcuIiwKICAgICAgICAgICAgICJCbGFuayIgPSAiIiwKICAgICAgICAgICAgICJOZXh0X0JsYW5rIiA9ICIiKSkrCiAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsbWF4KHB1bGwoYXNpYW5fc3ViZ3JvdXBzLFBlcmNlbnQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSkpKwogIGJhcl90aGVtZSgpKwogIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLjE4LDAuMDEpLCBsZWdlbmQucG9zaXRpb24gPSBjKDAuMTgsLjAxKSkrCiAgIGdlb21fdGV4dChkYXRhID0gYXNpYW5fdG90YWwsCiAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IDMsIHkgPSBQZXJjZW50ICsuNywgbGFiZWwgPSBsYWJlbCksCiAgICAgICAgICAgcGFyc2UgPSBUUlVFLAogICAgICAgICAgIGNvbG9yID0gIiMwMDgzOTMiLAogICAgICAgICAgICBzaXplID0gNCkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBwdWxsKGFzaWFuX3RvdGFsLCBQZXJjZW50KSksIGxpbmV0eXBlID0gMikgKwogIGdlb21fdGV4dChkYXRhID0gVVNfdG90YWwsCiAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IDMsIHkgPSBQZXJjZW50ICsuNywgbGFiZWwgPSBsYWJlbCksCiAgICAgICAgICAgcGFyc2UgPSBUUlVFLAogICAgICAgICAgIGNvbG9yID0gIiMwMDgzOTMiLCAKICAgICAgICAgICAgc2l6ZSA9IDQpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gcHVsbChVU190b3RhbCwgUGVyY2VudCkpLCBsaW5ldHlwZSA9IDMpCgogIGFzaWFuX2dlbmRlcl9zdWJncm91cF9wbG90CmBgYAoKCmBgYHtyfQoKbGF0aW54X2Zvcl9wbG90IDwtbGF0aW54X3N1Ymdyb3VwcyAlPiUKICBkcGx5cjo6c2VsZWN0KC1Hcm91cCkgJT4lCiAgZmlsdGVyKEdlbmRlciAhPSAiQWxsIikgJT4lCiAgZmlsdGVyKFJhY2VfRXRobmljaXR5ICE9ICJBbGxfcmFjZXMiKSAlPiUKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBzdHJfcmVwbGFjZSgKICAgICAgICAgICAgICAgICBzdHJpbmcgPSBSYWNlX0V0aG5pY2l0eSwgCiAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIlB1ZXJ0byBSaWNhbiwgRG9taW5pY2FuLCBDdWJhbiIsCiAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIlB1ZXJ0byBSaWNhbixcbkRvbWluaWNhbixcbkN1YmFuIikpICU+JQogIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9ICBmY3RfcmVvcmRlcihSYWNlX0V0aG5pY2l0eSwgUGVyY2VudCkpICU+JSAKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBmY3RfcmVsZXZlbChSYWNlX0V0aG5pY2l0eSwgIkxhdGlueCIpKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWWVhciwgdmFsdWVzX2Zyb20gPSBQZXJjZW50KSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKFJhY2VfRXRobmljaXR5LCBHZW5kZXIpLCAKICBuYW1lc190byA9ICJZZWFyIiAsIAogIHZhbHVlc190byA9ICJQZXJjZW50IikKCmxhdGlueF9nZW5kZXJfc3ViZ3JvdXBfcGxvdDwtbGF0aW54X2Zvcl9wbG90ICU+JQpnZ3Bsb3QoYWVzKHggPSBSYWNlX0V0aG5pY2l0eSwgeSA9IFBlcmNlbnQpKSArCmdlb21fY29sKGFlcyhmaWxsID0gR2VuZGVyKSwgcG9zaXRpb24gPSAiZG9kZ2UiKSsKICBsYWJzKHRpdGxlID0gIllPVVRIIERJU0NPTk5FQ1RJT04gQlkgTEFUSU5YIFNVQkdST1VQIEFORCBHRU5ERVIiLAogICAgc3VidGl0bGUgPSAiT1JERVJFRCBCWSBBVkVSQUdFIERJU0NPTk5FQ1RJT04gTEVWRUwgT0YgRkVNQUxFUyAmIE1BTEVTICgyMDE3LTIwMTgpIiwKICAgICAgICAgICB5ID0gIllPVVRIIERJU0NPTk5FQ1RJT04gKCUpIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGdlbmRlcl9wYWwpICsKICBzY2FsZV94X2Rpc2NyZXRlKAogIGxpbWl0cyA9IGMobGV2ZWxzKHB1bGwobGF0aW54X2Zvcl9wbG90LFJhY2VfRXRobmljaXR5KSlbMV0sCiAgICAgICAgICAgICAiQmxhbmsiLAogICAgICAgICAgICAgIk5leHRfQmxhbmsiLAogICAgICAgICAgICAgbGV2ZWxzKHB1bGwobGF0aW54X2Zvcl9wbG90LFJhY2VfRXRobmljaXR5KSlbMjoKICAgICAgICAgICAgIGxlbmd0aChsZXZlbHMocHVsbChsYXRpbnhfZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKSldKSwKICBsYWJlbHMgPSBjKCJMYXRpbngiID0gIkxhdGlueCBBdmcuIiwKICAgICAgICAgICAgICJCbGFuayIgPSAiIiwKICAgICAgICAgICAgICJOZXh0X0JsYW5rIiA9ICIiKSkrCiAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsbWF4KHB1bGwobGF0aW54X3N1Ymdyb3VwcyxQZXJjZW50KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkpKSsKICAKICBiYXJfdGhlbWUoKSsKICAgIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLjE4LDAuMDEpLCBsZWdlbmQucG9zaXRpb24gPSBjKDAuMTgsLjAxKSkrCiAgIGdlb21fdGV4dChkYXRhID0gbGF0aW54X3RvdGFsLAogICAgICAgICBtYXBwaW5nID0gYWVzKHggPSAzLCB5ID0gUGVyY2VudCArLjcsIGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgIHBhcnNlID0gVFJVRSwKICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwKICAgICAgICAgICAgc2l6ZSA9IDQpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gcHVsbChsYXRpbnhfdG90YWwsIFBlcmNlbnQpKSwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBVU190b3RhbCwKICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gMywgeSA9IFBlcmNlbnQgKy43LCBsYWJlbCA9IGxhYmVsKSwKICAgICAgICAgICBwYXJzZSA9IFRSVUUsCiAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsIAogICAgICAgICAgICBzaXplID0gNCkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBwdWxsKFVTX3RvdGFsLCBQZXJjZW50KSksIGxpbmV0eXBlID0gMykKCiAgbGF0aW54X2dlbmRlcl9zdWJncm91cF9wbG90CmBgYAoKIyMjIEZhY2V0ZWQgWWVhciBhbmQgR2VuZGVyIFBsb3RzCgpgYGB7cn0KYXNpYW5fdG90YWxbIlllYXIiXTwtYygiMjAxOCIpClVTX3RvdGFsWyJZZWFyIl08LWMoIjIwMTgiKQoKYGBgCgpgYGB7cn0KYXNpYW5fZm9yX3Bsb3QgPC1hc2lhbl9zdWJncm91cHMgJT4lCiAgZmlsdGVyKEdlbmRlciAhPSAiQWxsIikgJT4lCiAgZmlsdGVyKFJhY2VfRXRobmljaXR5ICE9ICJBbGxfcmFjZXMiKSAlPiUKICAgIGFkZF9yb3coUmFjZV9FdGhuaWNpdHkgPSAiSG1vbmciLAogICAgICAgICAgR2VuZGVyID0gIkZlbWFsZSIsCiAgICAgICAgICBZZWFyID0gMjAxNywKICAgICAgICAgIFBlcmNlbnQgPSBOQSkgJT4lCiAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gIGZjdF9yZW9yZGVyKFJhY2VfRXRobmljaXR5LCBQZXJjZW50KSkgJT4lIAogIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9IGZjdF9yZWxldmVsKFJhY2VfRXRobmljaXR5LCAiQXNpYW4iKSkgJT4lCiAgc2VsZWN0KC1Hcm91cCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFllYXIsIHZhbHVlc19mcm9tID0gUGVyY2VudCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtYyhSYWNlX0V0aG5pY2l0eSwgR2VuZGVyKSwgCiAgbmFtZXNfdG8gPSAiWWVhciIgLCAKICB2YWx1ZXNfdG8gPSAiUGVyY2VudCIpCgoKYXNpYW5fZ2VuZGVyX3N1Ymdyb3VwX3Bsb3RfZmFjZXRfeWVhcjwtYXNpYW5fZm9yX3Bsb3QgJT4lCmdncGxvdChhZXMoeCA9IFJhY2VfRXRobmljaXR5LCB5ID0gUGVyY2VudCkpICsKIGdlb21fY29sKGFlcyhmaWxsID0gR2VuZGVyKSwgcG9zaXRpb24gPSAiZG9kZ2UiKSsKICBmYWNldF93cmFwKH5ZZWFyLCBzY2FsZXMgPSAiZnJlZSIpICsKICBsYWJzKHRpdGxlID0gIkFTSUFOIFNVQkdST1VQIFlPVVRIIERJU0NPTk5FQ1RJT04gQlkgR0VOREVSIiwKICAgIHN1YnRpdGxlID0gIk9SREVSRUQgQlkgQVZFUkFHRSBESVNDT05ORUNUSU9OIExFVkVMIE9GIEZFTUFMRVMgJiBNQUxFUyAoLCAyMDE3LTIwMTgpIiwKICAgICAgICAgICB5ID0gIllPVVRIIERJU0NPTk5FQ1RJT04gKCUpIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGdlbmRlcl9wYWwpICsKICBzY2FsZV94X2Rpc2NyZXRlKAogIGxpbWl0cyA9IGMobGV2ZWxzKHB1bGwoYXNpYW5fZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsxXSwKICAgICAgICAgICAgICJCbGFuayIsCiAgICAgICAgICAgICBsZXZlbHMocHVsbChhc2lhbl9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpWzI6CiAgICAgICAgICAgICBsZW5ndGgobGV2ZWxzKHB1bGwoYXNpYW5fZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKSldKSwKICBsYWJlbHMgPSBjKCJBc2lhbiIgPSAiQXNpYW4gQXZnLiIsCiAgICAgICAgICAgICAiQmxhbmsiID0gIiIpKSsKICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCxtYXgocHVsbChhc2lhbl9zdWJncm91cHMsUGVyY2VudCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKSkrCiAgYmFyX3RoZW1lKCkrCiAgIGdlb21fdGV4dChkYXRhID0gYXNpYW5fdG90YWwsCiAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IDMuMywgeSA9IFBlcmNlbnQgKy43LCBsYWJlbCA9IGxhYmVsKSwKICAgICAgICAgICBwYXJzZSA9IFRSVUUsCiAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsCiAgICAgICAgICAgIHNpemUgPSAzKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IHB1bGwoYXNpYW5fdG90YWwsIFBlcmNlbnQpKSwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBVU190b3RhbCwKICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gMywgeSA9IFBlcmNlbnQgKy43LCBsYWJlbCA9IGxhYmVsKSwKICAgICAgICAgICBwYXJzZSA9IFRSVUUsCiAgICAgICAgICAgY29sb3IgPSAiIzAwODM5MyIsIAogICAgICAgICAgICBzaXplID0gMykgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBwdWxsKFVTX3RvdGFsLCBQZXJjZW50KSksIGxpbmV0eXBlID0gMykKCmBgYAoKYGBge3J9CmFzaWFuX2dlbmRlcl9zdWJncm91cF9wbG90X2ZhY2V0X3llYXIKYGBgCgpgYGB7cn0KYXNpYW5fZm9yX3Bsb3QgPC1hc2lhbl9zdWJncm91cHMgJT4lCiAgZmlsdGVyKEdlbmRlciAhPSAiQWxsIikgJT4lCiAgZmlsdGVyKFJhY2VfRXRobmljaXR5ICE9ICJBbGxfcmFjZXMiKSAlPiUKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSAgZmN0X3Jlb3JkZXIoUmFjZV9FdGhuaWNpdHksIFBlcmNlbnQpKSAlPiUgCiAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gZmN0X3JlbGV2ZWwoUmFjZV9FdGhuaWNpdHksICJBc2lhbiIpKSAlPiUKICBzZWxlY3QoLUdyb3VwKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWWVhciwgdmFsdWVzX2Zyb20gPSBQZXJjZW50KSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKFJhY2VfRXRobmljaXR5LCBHZW5kZXIpLCAKICBuYW1lc190byA9ICJZZWFyIiAsIAogIHZhbHVlc190byA9ICJQZXJjZW50IikKCmFzaWFuX2dlbmRlcl9zdWJncm91cF9wbG90X2ZhY2V0X3NleDwtYXNpYW5fZm9yX3Bsb3QgJT4lCmdncGxvdChhZXMoeCA9IFJhY2VfRXRobmljaXR5LCB5ID0gUGVyY2VudCwgZmlsbCA9IFllYXIpKSArCiBnZW9tX2NvbChhZXMoZmlsbCA9IFllYXIpLCBwb3NpdGlvbiA9ICJkb2RnZSIpKwogIGZhY2V0X3dyYXAofkdlbmRlciwgc2NhbGVzID0gImZyZWUiKSArCiAgbGFicyh0aXRsZSA9ICJBU0lBTiBTVUJHUk9VUCBZT1VUSCBESVNDT05ORUNUSU9OIEJZIEdFTkRFUiIsCiAgICBzdWJ0aXRsZSA9ICJPUkRFUkVEIEJZIEFWRVJBR0UgRElTQ09OTkVDVElPTiBMRVZFTCBPRiAyMDE3ICYgMjAxOCIsCiAgICAgICAgICAgeSA9ICJZT1VUSCBESVNDT05ORUNUSU9OICglKSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjdXN0b21fcGFsKSArCiAgc2NhbGVfeF9kaXNjcmV0ZSgKICBsaW1pdHMgPSBjKGxldmVscyhwdWxsKGFzaWFuX2Zvcl9wbG90LFJhY2VfRXRobmljaXR5KSlbMV0sCiAgICAgICAgICAgICAiQmxhbmsiLAogICAgICAgICAgICAgbGV2ZWxzKHB1bGwoYXNpYW5fZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsyOgogICAgICAgICAgICAgbGVuZ3RoKGxldmVscyhwdWxsKGFzaWFuX2Zvcl9wbG90LFJhY2VfRXRobmljaXR5KSkpXSksCiAgbGFiZWxzID0gYygiQXNpYW4iID0gIkFzaWFuIEF2Zy4iLAogICAgICAgICAgICAgIkJsYW5rIiA9ICIiKSkrCiAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsbWF4KHB1bGwoYXNpYW5fZm9yX3Bsb3QsUGVyY2VudCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKSkrCiAgYmFyX3RoZW1lKCkrCiAgIGdlb21fdGV4dChkYXRhID0gYXNpYW5fdG90YWwsCiAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IDMuMywgeSA9IFBlcmNlbnQgKy43LCBsYWJlbCA9IGxhYmVsKSwKICAgICAgICAgICBwYXJzZSA9IFRSVUUsCiAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCAKICAgICAgICAgICAgc2l6ZSA9IDMpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gcHVsbChhc2lhbl90b3RhbCwgUGVyY2VudCkpLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3RleHQoZGF0YSA9IFVTX3RvdGFsLAogICAgICAgICBtYXBwaW5nID0gYWVzKHggPSAzLCB5ID0gUGVyY2VudCArLjcsIGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgIHBhcnNlID0gVFJVRSwKICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIAogICAgICAgICAgICBzaXplID0gMykgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBwdWxsKFVTX3RvdGFsLCBQZXJjZW50KSksIGxpbmV0eXBlID0gMykKCmBgYAoKYGBge3J9CmFzaWFuX2dlbmRlcl9zdWJncm91cF9wbG90X2ZhY2V0X3NleAoKYGBgCgoKYGBge3J9CgpsYXRpbnhfdG90YWwKVVNfdG90YWwgCgpsYXRpbnhfdG90YWxbIkdlbmRlciJdPC1jKCJNYWxlIikKbGF0aW54X3RvdGFsWyJZZWFyIl08LWMoIjIwMTgiKQpgYGAKCmBgYHtyfQpsYXRpbnhfZm9yX3Bsb3QgPC1sYXRpbnhfc3ViZ3JvdXBzICU+JQogIGZpbHRlcihHZW5kZXIgIT0gIkFsbCIpICU+JQogIGZpbHRlcihSYWNlX0V0aG5pY2l0eSAhPSAiQWxsX3JhY2VzIikgJT4lCiAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gc3RyX3JlcGxhY2UoCiAgICAgICAgICAgICAgICAgc3RyaW5nID0gUmFjZV9FdGhuaWNpdHksIAogICAgICAgICAgICAgICAgcGF0dGVybiA9ICJQdWVydG8gUmljYW4sIERvbWluaWNhbiwgQ3ViYW4iLAogICAgICAgICAgICByZXBsYWNlbWVudCA9ICJQdWVydG8gUmljYW4sXG5Eb21pbmljYW4sXG5DdWJhbiIpKSAlPiUKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSAgZmN0X3Jlb3JkZXIoUmFjZV9FdGhuaWNpdHksIFBlcmNlbnQpKSAlPiUgCiAgbXV0YXRlKFJhY2VfRXRobmljaXR5ID0gZmN0X3JlbGV2ZWwoUmFjZV9FdGhuaWNpdHksICJMYXRpbngiKSkgJT4lCiAgc2VsZWN0KC1Hcm91cCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFllYXIsIHZhbHVlc19mcm9tID0gUGVyY2VudCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtYyhSYWNlX0V0aG5pY2l0eSwgR2VuZGVyKSwgCiAgbmFtZXNfdG8gPSAiWWVhciIgLCAKICB2YWx1ZXNfdG8gPSAiUGVyY2VudCIpCgoKbGF0aW54X2dlbmRlcl9zdWJncm91cF9wbG90X2ZhY2V0X3llYXI8LWxhdGlueF9mb3JfcGxvdCAlPiUKZ2dwbG90KGFlcyh4ID0gUmFjZV9FdGhuaWNpdHksIHkgPSBQZXJjZW50KSkgKwogZ2VvbV9jb2woYWVzKGZpbGwgPSBHZW5kZXIpLCBwb3NpdGlvbiA9ICJkb2RnZSIpKwogIGZhY2V0X3dyYXAoflllYXIsIHNjYWxlcyA9ICJmcmVlIikgKwogIGxhYnModGl0bGUgPSAiTEFUSU5YIFNVQkdST1VQIFlPVVRIIERJU0NPTk5FQ1RJT04gQlkgR0VOREVSIiwKICAgIHN1YnRpdGxlID0gIk9SREVSRUQgQlkgQVZFUkFHRSBESVNDT05ORUNUSU9OIExFVkVMIE9GIEZFTUFMRVMgJiBNQUxFUyAoLCAyMDE3LTIwMTgpIiwKICAgICAgICAgICB5ID0gIllPVVRIIERJU0NPTk5FQ1RJT04gKCUpIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGdlbmRlcl9wYWwpICsKICBzY2FsZV94X2Rpc2NyZXRlKAogIGxpbWl0cyA9IGMobGV2ZWxzKHB1bGwobGF0aW54X2Zvcl9wbG90LFJhY2VfRXRobmljaXR5KSlbMV0sCiAgICAgICAgICAgICAiQmxhbmsiLAogICAgICAgICAgICAgbGV2ZWxzKHB1bGwobGF0aW54X2Zvcl9wbG90LFJhY2VfRXRobmljaXR5KSlbMjoKICAgICAgICAgICAgIGxlbmd0aChsZXZlbHMocHVsbChsYXRpbnhfZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKSldKSwKICBsYWJlbHMgPSBjKCJMYXRpbngiID0gIkxhdGlueCBBdmcuIiwKICAgICAgICAgICAgICJCbGFuayIgPSAiIikpKwogICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLG1heChwdWxsKGxhdGlueF9zdWJncm91cHMsUGVyY2VudCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKSkrCiAgYmFyX3RoZW1lKCkrCiAgIGdlb21fdGV4dChkYXRhID0gbGF0aW54X3RvdGFsLAogICAgICAgICBtYXBwaW5nID0gYWVzKHggPSAzLjMsIHkgPSBQZXJjZW50ICsuNywgbGFiZWwgPSBsYWJlbCksCiAgICAgICAgICAgcGFyc2UgPSBUUlVFLAogICAgICAgICAgIGNvbG9yID0gIiMwMDgzOTMiLAogICAgICAgICAgICBzaXplID0gMykgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBwdWxsKGxhdGlueF90b3RhbCwgUGVyY2VudCkpLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3RleHQoZGF0YSA9IFVTX3RvdGFsLAogICAgICAgICBtYXBwaW5nID0gYWVzKHggPSAzLCB5ID0gUGVyY2VudCArLjcsIGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgIHBhcnNlID0gVFJVRSwKICAgICAgICAgICBjb2xvciA9ICIjMDA4MzkzIiwgCiAgICAgICAgICAgIHNpemUgPSAzKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IHB1bGwoVVNfdG90YWwsIFBlcmNlbnQpKSwgbGluZXR5cGUgPSAzKQoKYGBgCgpgYGB7cn0KbGF0aW54X2dlbmRlcl9zdWJncm91cF9wbG90X2ZhY2V0X3llYXIKYGBgCgpgYGB7cn0KbGF0aW54X2Zvcl9wbG90IDwtbGF0aW54X3N1Ymdyb3VwcyAlPiUKCiAgZmlsdGVyKEdlbmRlciAhPSAiQWxsIikgJT4lCiAgZmlsdGVyKFJhY2VfRXRobmljaXR5ICE9ICJBbGxfcmFjZXMiKSAlPiUKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBzdHJfcmVwbGFjZSgKICAgICAgICAgICAgICAgICBzdHJpbmcgPSBSYWNlX0V0aG5pY2l0eSwgCiAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIlB1ZXJ0byBSaWNhbiwgRG9taW5pY2FuLCBDdWJhbiIsCiAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIlB1ZXJ0byBSaWNhbixcbkRvbWluaWNhbixcbkN1YmFuIikpICU+JQogIG11dGF0ZShSYWNlX0V0aG5pY2l0eSA9ICBmY3RfcmVvcmRlcihSYWNlX0V0aG5pY2l0eSwgUGVyY2VudCkpICU+JSAKICBtdXRhdGUoUmFjZV9FdGhuaWNpdHkgPSBmY3RfcmVsZXZlbChSYWNlX0V0aG5pY2l0eSwgIkxhdGlueCIpKSAlPiUKICBzZWxlY3QoLUdyb3VwKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWWVhciwgdmFsdWVzX2Zyb20gPSBQZXJjZW50KSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jKFJhY2VfRXRobmljaXR5LCBHZW5kZXIpLCAKICBuYW1lc190byA9ICJZZWFyIiAsIAogIHZhbHVlc190byA9ICJQZXJjZW50IikKCmxhdGlueF9nZW5kZXJfc3ViZ3JvdXBfcGxvdF9mYWNldF9zZXg8LWxhdGlueF9mb3JfcGxvdCAlPiUKZ2dwbG90KGFlcyh4ID0gUmFjZV9FdGhuaWNpdHksIHkgPSBQZXJjZW50LCBmaWxsID0gWWVhcikpICsKIGdlb21fY29sKGFlcyhmaWxsID0gWWVhciksIHBvc2l0aW9uID0gImRvZGdlIikrCiAgZmFjZXRfd3JhcCh+R2VuZGVyLCBzY2FsZXMgPSAiZnJlZSIpICsKICBsYWJzKHRpdGxlID0gIiBMQVRJTlggU1VCR1JPVVAgWU9VVEggRElTQ09OTkVDVElPTiBCWSBHRU5ERVIiLAogICAgc3VidGl0bGUgPSAiT1JERVJFRCBCWSBBVkVSQUdFIERJU0NPTk5FQ1RJT04gTEVWRUwgT0YgMjAxNyAmIDIwMTgiLAogICAgICAgICAgIHkgPSAiWU9VVEggRElTQ09OTkVDVElPTiAoJSkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY3VzdG9tX3BhbCkgKwogIHNjYWxlX3hfZGlzY3JldGUoCiAgbGltaXRzID0gYyhsZXZlbHMocHVsbChsYXRpbnhfZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsxXSwKICAgICAgICAgICAgICJCbGFuayIsCiAgICAgICAgICAgICBsZXZlbHMocHVsbChsYXRpbnhfZm9yX3Bsb3QsUmFjZV9FdGhuaWNpdHkpKVsyOgogICAgICAgICAgICAgbGVuZ3RoKGxldmVscyhwdWxsKGxhdGlueF9mb3JfcGxvdCxSYWNlX0V0aG5pY2l0eSkpKV0pLAogIGxhYmVscyA9IGMoIkxhdGlueCIgPSAiTGF0aW54IEF2Zy4iLAogICAgICAgICAgICAgIkJsYW5rIiA9ICIiKSkrCiAgYmFyX3RoZW1lKCkrCiAgZ2VvbV90ZXh0KGRhdGEgPSBsYXRpbnhfdG90YWwsCiAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IDMsIHkgPSBQZXJjZW50ICsuNywgbGFiZWwgPSBsYWJlbCksCiAgICAgICAgICAgcGFyc2UgPSBUUlVFLAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgCiAgICAgICAgICAgIHNpemUgPSAzKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IHB1bGwobGF0aW54X3RvdGFsLCBQZXJjZW50KSksIGxpbmV0eXBlID0gMikgKwogIGdlb21fdGV4dChkYXRhID0gVVNfdG90YWwsCiAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IDMsIHkgPSBQZXJjZW50ICsuNywgbGFiZWwgPSBsYWJlbCksCiAgICAgICAgICAgcGFyc2UgPSBUUlVFLAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgCiAgICAgICAgICAgIHNpemUgPSAzKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IHB1bGwoVVNfdG90YWwsIFBlcmNlbnQpKSwgbGluZXR5cGUgPSAzKQpgYGAKCgpgYGB7cn0KbGF0aW54X2dlbmRlcl9zdWJncm91cF9wbG90X2ZhY2V0X3NleApgYGAKCgoKCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gYXNpYW5fdG90YWwpLCBsaW5ldHlwZSA9IDIpICsKZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IFVTX3RvdGFsKSwgbGluZXR5cGUgPSAzKQoKZGF0X3RleHQgPC0gZGF0YS5mcmFtZSgKICBsYWJlbCA9IGMoICdib2xkKCJVUyAyMDE3IEFWRyBSQVRFIiknKSwKICBHZW5kZXIgPSBjKCJGZW1hbGUiKSwKICBZZWFyID0gYygiMjAxNyIpKQpwbG90IDwtcGxvdCArIGdlb21fdGV4dCgKICBkYXRhICAgID0gZGF0X3RleHQsCiAgbWFwcGluZyA9IGFlcyh4ID0gMi41LCB5ID0gVVNfdG90YWwgKy43LCBsYWJlbCA9IGxhYmVsKSwKICBwYXJzZSA9IFRSVUUsCiAgY29sb3IgPSAiIzAwODM5MyIsIHNpemUgPSA0KQoKZGF0X3RleHQgPC0gZGF0YS5mcmFtZSgKICBsYWJlbCA9IGMoICdib2xkKCJBU0lBTiAyMDE3IFJBVEUiKScpLAogIEdlbmRlciA9IGMoIkZlbWFsZSIpLAogIFllYXIgPSBjKCIyMDE3IikpCnBsb3QgKyBnZW9tX3RleHQoCiAgZGF0YSAgICA9IGRhdF90ZXh0LAogIG1hcHBpbmcgPSBhZXMoeCA9IDIuNSwgeSA9IGFzaWFuX3RvdGFsICsuNywgbGFiZWwgPSBsYWJlbCksCiAgcGFyc2UgPSBUUlVFLAogIGNvbG9yID0gIiMwMDgzOTMiLCBzaXplID0gNCkKCmBgYAoKCgojIyAqKkRhdGEgQW5hbHlzaXMqKgoqKiogCgpgYGB7ciwgZWNobyA9IEZBTFNFfQojIFRvIGFsbG93IHN0YXJ0aW5nIGF0IHRoaXMgc2VjdGlvbjoKbG9hZChoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkX2RhdGEucmRhIikpCmBgYAoKKipSZXBlYXRlZCBDcm9zcy1zZWN0aW9uYWwgRGF0YSoqCgpXZSBoYXZlIHBvb2xlZCAocmVwZWF0ZWQpIFtjcm9zcy1zZWN0aW9uYWxdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Nyb3NzLXNlY3Rpb25hbF9kYXRhP29sZGZvcm1hdD10cnVlKSBkYXRhLgoKVGhpcyBpcyBkYXRhIHByb2R1Y2VkIGZyb20gcmVwZWF0ZWQgbWVhc3VyZW1lbnQgb2YgYSBbcG9wdWxhdGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUG9wdWxhdGlvbj9vbGRmb3JtYXQ9dHJ1ZSkgb3ZlciB0aW1lLgoKSXQgaXMgb2Z0ZW4gaW5mZWFzaWJsZSB0byBjb2xsZWN0IGRhdGEgZm9yIGFuIGVudGlyZSBwb3B1bGF0aW9uIGF0IG9uY2UuIEhvd2V2ZXIsIHdlIGNhbiBzdGlsbCBvYnRhaW4gbWVhbmluZ2Z1bCBtZWFzdXJlcyB1c2luZyBhIHJhbmRvbSBbc2FtcGxlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TYW1wbGluZ18oc3RhdGlzdGljcyk/b2xkZm9ybWF0PXRydWUpIG9mIHRoZSBwb3B1bGF0aW9uLiAKCkF0IHNwZWNpZmljIHRpbWUtcG9pbnRzLCBkYXRhIGlzIGNvbGxlY3RlZCBmcm9tIGEgc2FtcGxlIG9mIHRoZSBwb3B1bGF0aW9uLiBUaGUgaW5kaXZpZHVhbHMgaW4gZWFjaCBzYW1wbGUgYXJlIG5vdCBuZWNlc3NhcmlseSB0aGUgc2FtZSBpbmRpdmlkdWFscy4gVGhpcyBzZXBhcmF0ZXMgcG9vbGVkIGNyb3NzLXNlY3Rpb25hbCBkYXRhIGZyb20gcGFuZWwgZGF0YSwgd2hpY2ggaXMgbG9uZ2l0dWRpbmFsIGRhdGEgZnJvbSByZXBlYXRlZCBtZWFzdXJlbWVudCBvZiB0aGUgc2FtZSBwZW9wbGUuICAgCgpCeSBzYW1wbGluZyBmcm9tIGEgcG9wdWxhdGlvbiBhdCBtdWx0aXBsZSB0aW1lIHBvaW50cywgd2UgY2FuIGdlbmVyYXRlIHBvcHVsYXRpb24gbGV2ZWwgc3RhdGlzdGljcy4gQWx0aG91Z2ggdGhlc2Ugc3RhdGlzdGljcyBoYXZlIHNvbWUgcmFuZG9tIGVycm9yLCB0aGV5IGNhbiBwcm92aWRlIGluc2lnaHQgaW50byBob3cgdGhlIG1lYXN1cmUgdmFyaWFibGUgaXMgY2hhbmdpbmcgaW4gYSBwb3B1bGF0aW9uIG92ZXIgdGltZS4KCldlIGNhbiBhY2NvbXBsaXNoIHRoaXMgYnkgcGxvdHRpbmcgdGhlIG1lYXN1cmVkIHZhbHVlcyBvdmVyIHRpbWUuIFNvbWV0aW1lcywgaG93ZXZlciwgdGhlIHRyZW5kIGlzbid0IGV4YWN0bHkgY2xlYXIuIEZvcnR1bmF0ZWx5LCB0aGVyZSBhcmUgc3RhdGlzdGljYWwgbWV0aG9kcyB0byByZXNvbHZlIHRoaXMgaXNzdWUuCgpUaGUgTWFubi1LZW5kYWxsIHRyZW5kIHRlc3TigJRhIHZhcmlhdGlvbiBvZiB0aGUgW0tlbmRhbGwgcmFuayBjb3JyZWxhdGlvbiBjb2VmZmljaWVudF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvS2VuZGFsbF9yYW5rX2NvcnJlbGF0aW9uX2NvZWZmaWNpZW50P29sZGZvcm1hdD10cnVlKeKAlHRlc3RzIHdoZXRoZXIgdGhlcmUgaXMgYSBtb25vdG9uaWMgYXNzb2NpYXRpb24sIGFuIGFzc29jaWF0aW9uIHRoYXQgZG9lcyBub3QgaW5jcmVhc2Ugb3IgZGVjcmVhc2UgYnV0IHJlbWFpbnMgc3RhdGljIGFjcm9zcyBhIGRpbWVuc2lvbi4KClJlY2FsbCB0aGUgeW91dGggZGlzY29ubmVjdGlvbiByYXRlcyBmb3IgTmF0aXZlIEFtZXJpY2Fucywgc29tZSBvZiB0aGUgaGlnaGVzdCBpbiB0aGUgZmlyc3QgdGFibGUgd2UgZXhhbWluZWQuIAoKYGBge3J9Ck1ham9yX3JhY2lhbF9ldGhuaWNfZ3JvdXBzCmBgYAoKTGV0J3MgY29uZHVjdCBhIE1hbm4tS2VuZGFsbCB0ZXN0IGZvciB0cmVuZC4KCldlIGNhbiBhY2NvbXBsaXNoIHRoaXMgd2l0aCB0aGUgYEtlbmRhbGw6Ok1hbm5LZW5kYWxsKClgIGZ1bmN0aW9uLiBUaGUgYEtlbmRhbGw6Ok1hbm5LZW5kYWxsKClgIGFjY2VwdHMgYSB2ZWN0b3Igb2YgZGF0YSBmb3Igd2hpY2ggYSB0cmVuZCBtYXkgYmUgb2JzZXJ2ZWQuIFtDb25zdWx0aW5nIHRoZSBkb2N1bWVudGF0aW9uIGZvciB0aGUgYEtlbmRhbGw6Ok1hbm5LZW5kYWxsKClgIGZ1bmN0aW9uIGF2YWlsYWJsZSBvbiBDUkFOXShodHRwczovL3JkcnIuaW8vY3Jhbi9LZW5kYWxsL21hbi9NYW5uS2VuZGFsbC5odG1sKSwgd2UgY2FuICJ0ZXN0IGZvciBhIGEgbW9ub3RvbmljIHRyZW5kIGluIGEgdGltZSBzZXJpZXMiLgoKCgpgYGB7cn0KbWFqb3JfZ3JvdXBzX2xvbmcgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiQWxsIiwKIFJhY2VfRXRobmljaXR5ID09ICJOYXRpdmUgQW1lcmljYW4iKSAlPiUKICBwdWxsKFBlcmNlbnQpICU+JQogIE1hbm5LZW5kYWxsKC4pICU+JQogIHN1bW1hcnkoKQoKYGBgCgoKVGhlcmUgZG9lcyBub3QgYXBwZWFyIHRvIGJlIGEgY2hhbmdlIGluIHRoZSB0cmVuZC4gSG93ZXZlciwgaXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHdlIG9ubHkgaGF2ZSBgciBsZW5ndGgobWFqb3JfZ3JvdXBzX2xvbmcgJT4lIGZpbHRlcihHZW5kZXIgPT0gIkFsbCIsIFJhY2VfRXRobmljaXR5ID09ICJOYXRpdmUgQW1lcmljYW4iKSAlPiUgcHVsbChQZXJjZW50KSlgIG9ic2VydmF0aW9ucy4KCldlIGNhbiBhbHNvIGV4cGxvcmUgdGhlIHRyZW5kIHVzaW5nIFtzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1NpbXBsZV9saW5lYXJfcmVncmVzc2lvbj9vbGRmb3JtYXQ9dHJ1ZSkuIAoKCmBgYHtyfQptYWpvcl9ncm91cHNfbG9uZyAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJBbGwiLAogUmFjZV9FdGhuaWNpdHkgPT0gIk5hdGl2ZSBBbWVyaWNhbiIpICU+JQogIGxtKFBlcmNlbnQgfiBZZWFyLCBkYXRhID0gLikgJT4lCiAgc3VtbWFyeSgpCmBgYAoKCkZvciBlYWNoIG9uZSB5ZWFyIGNoYW5nZSwgdGhlIG1lYW4gaW5jcmVhc2UgaW4gZGlzY29ubmVjdGlvbiByYXRlcyBpcwpgciAobWFqb3JfZ3JvdXBzX2xvbmclPiUgZmlsdGVyKEdlbmRlciA9PSAiQWxsIiwgUmFjZV9FdGhuaWNpdHkgPT0gIk5hdGl2ZSBBbWVyaWNhbiIpICU+JSBsbShQZXJjZW50IH4gWWVhciwgZGF0YSA9IC4pKVtbImNvZWZmaWNpZW50cyJdXVsiWWVhciJdYAoKIFRoaXMgcmVsYXRpb25zaGlwIGlzIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LiBBZ2Fpbiwgd2UgYXJlIGxhcmdlbHkgbGltaXRlZCBieSB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiB0aGlzIGRhdGFzZXQuIAoKV2UgY2FuIHZpc3VhbGl6ZSB0aGUgcmVsYXRpb25zaGlwIGFib3ZlLgoKYGBge3J9Cm1ham9yX2dyb3Vwc19sb25nICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIkFsbCIsCiBSYWNlX0V0aG5pY2l0eSA9PSAiTmF0aXZlIEFtZXJpY2FuIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IFBlcmNlbnQpKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAicmVkIikgKyAKICBnZW9tX3BvaW50KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDgsIDIwMTgsIGJ5ID0gMSksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgyMDA4LCAyMDE4LCBieSA9IDEpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDIwMDgsIDIwMTgpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIllvdXRoIERpc2Nvbm5lY3Rpb24gUmF0ZXMgb2YgTmF0aXZlIEFtZXJpY2FuIFlvdXRoIiwKICAgICAgIHN1YnRpdGxlID0gIjIwMDggLSAyMDE3IiwKICAgICAgIHggPSAiWWVhciIsCiAgICAgICB5ID0gIkRpc2Nvbm5lY3Rpb24gUmF0ZSIpCmBgYAoKCkFzIHdlIGNhbiBzZWUsIHRoZXJlIGlzIGEgbGFyZ2UgYW1vdW50IG9mIHVuY2VydGFpbnR5IGFyb3VuZCB0aGUgZml0dGVkIGxpbmUuIAoKCgoKCgoKIyMgKipTdW1tYXJ5KioKKioqIAoKIyMjIFN1bW1hcnkgUGxvdAoKYGBge3J9CmxpYnJhcnkocGF0Y2h3b3JrKQpwbmcoZmlsZW5hbWUgPSBoZXJlOjpoZXJlKCJpbWciLCAibWFpbnBsb3QucG5nIiksCiAgICByZXMgPSAzMDAsIHdpZHRoID0gMTMuNSwgaGVpZ2h0ID0gMTQsIHVuaXRzID0gImluIikKKHBsb3Rfc3BhY2VyKCkgKyBwbG90X2dlbmRlcisgcGxvdF9zcGFjZXIoKSAgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDAuMywzLDAuMykpKSAvIChhc2lhbl9zdWJncm91cF9wbG90X3NpbXAgKyBhc2lhbl9nZW5kZXJfc3ViZ3JvdXBfcGxvdCkgLyhsYXRpbnhfc3ViZ3JvdXBfcGxvdF9zaW1wICsgbGF0aW54X2dlbmRlcl9zdWJncm91cF9wbG90KSArIAogIHBsb3RfbGF5b3V0KGhlaWdodHMgPWMoMiwgMS4zLCAxLjMpLCB3aWR0aHMgPSBjKDEuNSwgMi41LCAyLjUpKSAmICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPTE0KSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpKSYKIHBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJEZWVwZXIgSW5zZXBlY3Rpb24gUmV2ZWFscyBEaWZmZXJlbmNlcyBmb3IgWW91dGggRGlzY29ubmVjdGlvblxuIEFtb25nIFJhY2VzLCBFdGhuaWMgU3ViZ3JvdXBzLCBhbmQgR2VuZGVycyIsIHRoZW1lID0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjIsIGZhY2UgPSAiYm9sZCIpKSkKZGV2Lm9mZigpCgojJiB0aGVtZSA9IHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9MTQpLCBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSkrCmBgYAoKIyMgKipTdWdnZXN0ZWQgSG9tZXdvcmsqKgoqKiogCgoxKSBGaW5kIGFub3RoZXIgdGFibGUgaW4gdGhlIGRvY3VtZW50LiBGaW5kIGRpZmZlcmVuY2VzIGJldHdlZW4gZ3JvdXBzIHdpdGggdGhlIHByb2Nlc3MgZGVzY3JpYmVkIGFib3ZlLiAKCiMjICoqSGVscGZ1bCBMaW5rcyoqCioqKiAKCgphdm9jYWRvKlRoaXMgY29uY2VwdHMgbGlzdGVkIGhlcmUgbXVzdCBiZSByZXZpc2l0ZWQuKgoKCjx1PlRlcm1zIGFuZCBjb25jZXB0cyBjb3ZlcmVkOjwvdT4gIAoKW1RpZHl2ZXJzZV0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pICAKW1JTdHVkaW8gY2hlYXRzaGVldHNdKGh0dHBzOi8vcnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLykgIApbSW5mZXJlbmNlXShodHRwczovL3d3dy5icml0YW5uaWNhLmNvbS9zY2llbmNlL2luZmVyZW5jZS1zdGF0aXN0aWNzKSAgCltSZWdyZXNzaW9uXShodHRwczovL2xpbmRlbG9ldi5naXRodWIuaW8vdGVzdHMtYXMtbGluZWFyLykgIApbRGlmZmVyZW50IHR5cGVzIG9mIHJlZ3Jlc3Npb25dKGh0dHBzOi8vd3d3LmFuYWx5dGljc3ZpZGh5YS5jb20vYmxvZy8yMDE1LzA4L2NvbXByZWhlbnNpdmUtZ3VpZGUtcmVncmVzc2lvbi8pICAKW09yZGluYXJ5IGxlYXN0IHNxdWFyZXMgbWV0aG9kXShodHRwOi8vc2V0b3NhLmlvL2V2L29yZGluYXJ5LWxlYXN0LXNxdWFyZXMtcmVncmVzc2lvbi8pICAKW1Jlc2lkdWFsXShodHRwczovL3d3dy5zdGF0aXN0aWNzaG93dG8uZGF0YXNjaWVuY2VjZW50cmFsLmNvbS9yZXNpZHVhbC8pICAKCjx1PlBhY2thZ2VzIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5OiA8L3U+CgogUGFja2FnZSAgIHwgVXNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tClsqKmhlcmUqKl0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKSAgICAgICB8IHRvIGVhc2lseSBsb2FkIGFuZCBzYXZlIGRhdGEKWyoqdGlkeXZlcnNlKipdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZy8pICAgICAgfCBmb3IgZGF0YSBzY2llbmNlIG9wZXJhdGlvbnMKWyoqcGRmdG9vbHMqKl0oaHR0cHM6Ly9yZWFkci50aWR5dmVyc2Uub3JnLykgICAgICB8IHRvIG1hbmFnZSBQREYgZG9jdW1lbnRzClsqKm1hZ2ljayoqXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFnaWNrL3ZpZ25ldHRlcy9pbnRyby5odG1sI0tlcm5lbF9jb252b2x1dGlvbikgICAgICB8IGZvciBpbWFnZSBwcm9jZXNzaW5nIAoKIyMgQWNrbm93bGVkZ2VtZW50cwoKV2Ugd291bGQgbGlrZSB0byBhY2tub3dsZWRnZSBbVGFtYXIgTWVuZGVsc29uXShodHRwczovL3d3dy5qaHNwaC5lZHUvZmFjdWx0eS9kaXJlY3RvcnkvcHJvZmlsZS8xNzcwL3RhbWFyLW1lbmRlbHNvbikgZm9yIGFzc2lzdGluZyBpbiBmcmFtaW5nIHRoZSBtYWpvciBkaXJlY3Rpb24gb2YgdGhlIGNhc2Ugc3R1ZHkuCgpXZSB3b3VsZCBhbHNvIGxpa2UgdG8gYWNrbm93bGVkZ2UgdGhlIFtCbG9vbWJlcmcgQW1lcmljYW4gSGVhbHRoIEluaXRpYXRpdmVdKGh0dHBzOi8vYW1lcmljYW5oZWFsdGguamh1LmVkdS8pIGZvciBmdW5kaW5nIHRoaXMgd29yay4g